⊙ 데이터타입: VARCHAR2 에 숫자를 넣으면?
숫자를 VARCHAR2 나 CHAR 에 넣어도 된다.
숫자를 사용하는 목적은 연산을 하기 위해서 인데, 문자형 데이터 타입을
사용하면 연산을 할 수 없다.
그런데, 사실은 문자 타입도 연산을 할 수 있다.
오라클이 내부적으로 문자 타입을 숫자 타입으로 변환하기 때문이다.
이 변환은 오라클 버전 별로 차이가 있으므로 항상 적용되는 것은 아니다.
사칙연산은 물론이고 SUM(), AVG(), 심지어 표준편차를 구하는 STDDEV() 함수도
문자가 적용된다.
확인해 보자.
테이블을 만들자.
CREATE TABLE TTT
(
VC1 VARCHAR2(10)
, VC2 VARCHAR2(10)
);
값을 넣자. 소숫점도 넣어보자.
INSERT INTO TTT VALUES ('5','7');
INSERT INTO TTT VALUES ('8.5','11.3');
INSERT INTO TTT VALUES ('10','20');
INSERT INTO TTT VALUES ('15','25');
COMMIT;
더하기를 해보자.
SELECT VC1, VC2, VC1+VC2 FROM TTT;
VC1 | VC2 | VC1+VC2 |
5 | 7 | 12 |
8.5 | 11.3 | 19.8 |
10 | 20 | 30 |
15 | 25 | 40 |
더하기가 잘 됐다.
표를 잘 보면 문자 정렬이 VC1, VC2 값은 왼쪽 정렬, 더한 값은 오를쪽 정렬로 되어 있다.
이는 문자를 숫자로 변환했음을 알 수 있다.
곱하기를 해보자.
SELECT VC1, VC2, VC1*VC2 FROM TTT;
VC1 | VC2 | VC1*VC2 |
5 | 7 | 35 |
8.5 | 11.3 | 96.05 |
10 | 20 | 200 |
15 | 25 | 375 |
잘 된다.
나누기를 해보자.
SELECT VC1, VC2, VC1/VC2 FROM TTT;
VC1 | VC2 | VC1/VC2 |
5 | 7 | 0.714285714 |
8.5 | 11.3 | 0.752212389 |
10 | 20 | 0.5 |
15 | 25 | 0.6 |
역시, 잘 된다.
빼기를 해보자.
SELECT VC1, VC2, VC1-VC2 FROM TTT;
VC1 | VC2 | VC1-VC2 |
5 | 7 | -2 |
8.5 | 11.3 | -2.8 |
10 | 20 | -10 |
15 | 25 | -10 |
너무 잘된다.
SUM() 은 될까?
SELECT SUM(VC1), SUM(VC2) FROM TTT;
SUM(VC1) | SUM(VC2) |
38.5 | 63.3 |
기대를 저버리지 않고 잘 됐다.
그럼, 평균은?
SELECT AVG(VC1), AVG(VC2) FROM TTT;
AVG(VC1) | AVG(VC2) |
9.625 | 15.825 |
두말하면 잔소리. 역시 잘된다.
이왕 하는 김에 표준편차도 해보자.
SELECT STDDEV(VC1), STDDEV(VC2) FROM TTT;
STDDEV(VC1) | STDDEV(VC2) |
4.150803135 | 8.164302379 |
하여간 잘된다.
최소값을 가져오는 MIN() 함수도 해볼까. 잘 될꺼야.
원래 값과 비교해 볼려고 UNION ALL 을 썼다.
SELECT VC1, VC2 FROM TTT
UNION ALL
SELECT MIN(VC1), MIN(VC2) FROM TTT;
VC1 | VC2 |
5 | 7 |
8.5 | 11.3 |
10 | 20 |
15 | 25 |
10 | 11.3 |
어! 결과가 좀 이상하다. 제일 작은 숫자가 5 인데. 왜 10 이 제일 작은 숫자로 나왔지?
왜 이렇게 나왔지? 앞에 함수들은 잘 됐는데...
혹시... 버그가 있는게 아닐까?.....
이왕 테슽 해보는거 최대값을 가져오는 MAX() 도 해보자.
SELECT VC1, VC2 FROM TTT
UNION ALL
SELECT MAX(VC1), MAX(VC2) FROM TTT;
VC1 | VC2 |
5 | 7 |
8.5 | 11.3 |
10 | 20 |
15 | 25 |
8.5 | 7 |
헉! 이것도 이상하네.. 15, 25 가 나와야 하는데 8.5, 7 이 나왔네...
더구나 7은 가장 작은 수인데....
정말 버그가 있는걸까?...
그런데, 아주 많은 사람들이 쓰고 있는 오라클인데 설마 이런 버그가 있을리가...
버그가 있었어도 벌써 고쳤겠지... 지금까지 그대로 있을려구...
에구.. 잘 모르겠다.
커피 한잔 하며 좀 쉬어야 겠다.
잠깐, 앞에 함수들과 뭔가 다른게 있나?.....
잘 생각해 보자. 앞에 쓴 SUM(), AVG(), STDDEV() 함수는 모두 숫자를 계산하는 함수들인데.
MIN() 도 마찬가지 아닌가?
작다, 크다... 아!.... 문자도 해당되는거 같은데.. A 와 B 를 비교할 수 있나?.
A = B, A > B, A < B 이런 것들...
해보면 되지..
SELECT 'A' = 'B' FROM DUAL;
ORA-00923: FROM 키워드가 필요한 위치에 없습니다.
앵!.. 왠 에러가?.....
이렇게는 할 수 없나보네...
그럼, WHERE 절에 넣어볼까...
SELECT * FROM DUAL
WHERE 'A' = 'B';
이 건 에러는 않나는데.. 결과도 없네..
비교 테스트 해보는 것도 쉽지 않군...
어떻게 비교하지?....
아! CASE 를 써 볼까...
우선 'A' 하고 'A' 를 비교해서 같으면 'TRUE' 를, 다르면 'FALSE' 를 보여주게 하자.
SELECT CASE WHEN 'A' = 'A' THEN 'TRUE' ELSE 'FALSE' END FROM DUAL;
CASEWHEN'A'='A'THEN'TRUE'ELSE'FALSE'END |
TRUE |
오호! 잘된다.
그럼, 'A' = 'B' 를 비교해보자.
SELECT CASE WHEN 'A' = 'B' THEN 'TRUE' ELSE 'FALSE' END FROM DUAL;
CASEWHEN'A'='B'THEN'TRUE'ELSE'FALSE'END |
FALSE |
맞네.. 'A' 와 'B' 는 다르지.
그럼, 'A' > 'B', 'A' < 'B' 도 비교해보자.
SELECT CASE WHEN 'A' > 'B' THEN 'TRUE' ELSE 'FALSE' END FROM DUAL;
CASEWHEN'A'>'B'THEN'TRUE'ELSE'FALSE'END |
FALSE |
SELECT CASE WHEN 'A' < 'B' THEN 'TRUE' ELSE 'FALSE' END FROM DUAL;
CASEWHEN'A'<'B'THEN'TRUE'ELSE'FALSE'END |
TRUE |
문자도 비교가 되는군.
그럼, MIN(), MAX() 함수는 문자도 비교해서 보여주는 구나.
여기서 VC1, VC2 모두 문자 데이터 타입이니, 문자로 비교해서 보여주면...
결과를 다시 살펴보자.
VC1 | VC2 |
5 | 7 |
8.5 | 11.3 |
10 | 20 |
15 | 25 |
10 | 11.3 |
문자는 맨 앞자부터 비교하니 VC1 에서는 1로 시작하는게 10, 15 이고 이중 2번째 문자를
비교하니 10 이 가장 작군. VC2 의 11.3 도 마찬가지네.
그럼, 여기서 MIN(), MAX() 함수는 원래 VC1, VC2 의 데이터 타입이 문자이니
그대로 문자의 크고, 작음을 비교했구나....
원래 문제로 돌아가 보자.
문자 데이터 타입에 숫자를 넣을 수 있다고 해서 그렇게 하는게 맞는가?
오라클이 내부적으로 문자를 숫자로 변환하므로 내부 연산이 필요해서 적지만 성능에
악 영향을 미친다. 그리고 더 큰 문제는 앞의 테스트에서 처럼 MIN(), MAX() 같이
예상치 못한 결과가 나올 수 있다.
그러므로 문자는 문자 데이터 타입에, 숫자는 숫자 데이터 타입에 넣어야 한다.