336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

 

오라클에서 문자타입을 사용 하다 보면 CHAR, VARCHAR, VARCHAR2를 보실수 있습니다.

처음에는 아무생각 없이 쓰다가 어느순간 문제가 발생 해 검색을 하는 경우가 생길 거라 생각이 듭니다.

그 순간 이 포스팅을 보시고, 도움이 되셨으면 좋겠습니다.

(완전 완벽히 자세히 알려드리지는 못할 수 있지만 사용하는데 최대한 지장이 없도록 열심히 작성하였습니다!)

 

우선 간단하게 비교표를 보면,

 

CHAR는 고정형이고, VARCHAR는 가변형이라고 적혀있습니다.

고정형은 말그대로 고정적일때 사용해야 하고, 가변형은 변화가 있는 컬럼에 대해 사용해야 한다는 것입니다.

이 말이 처음에는 먼가 하실 수 있습니다.

(저도.. 그랬습니다.. 심지어 처음 배웠을때는 아 그런가보다 하고 넘겼던 것 같습니다..)

그래서 이해를 돕기 위해 예제를 한번 만들어봤습니다.

 

CREATE TABLE TEST_CHARACTER(
 T_CHAR CHAR(4),
 T_VARCHAR VARCHAR(4),
 T_VARCHAR2 VARCHAR2(4) 
);

 

INSERT INTO TEST_CHARACTER VALUES('A', 'A', 'A'); 

 

테스트 테이블을 만들고, 각각 CHAR, VARCHAR, VARCHAR2 문자형을 가지는 컬럼에 똑같은 문자 A를 넣습니다.

 

 

이 상태에서 고정형과 가변형의 차이를 볼 수 있게 셀렉트를 해보겠습니다.

 

SELECT  DECODE(T_CHAR, 'A   ', 'TRUE', 'FALSE')         T_CHAR,
           DECODE(T_VARCHAR, 'A   ', 'TRUE', 'FALSE')    T_VARCHAR,
           DECODE(T_VARCHAR2, 'A   ', 'TRUE', 'FALSE')  T_VARCHAR2
FROM   TEST_CHARACTER;

 

※ 참고로 DECODE 함수는 IF문 같은 함수입니다. DECODE(컬럼, '비교값', '같으면 요기', '다르면 요기') 

위와 같이 셀렉트를 하면 아래와 같은 결과가 나옵니다.

 

 

간략하게 설명을 드리면,

비교값의 문자는 'A∨∨∨' (A공백백공백) 입니다.

공백이 포함되자 CHAR 같은 경우에는 TRUE가 나왔고, VARCHAR나 VARCHAR2는 FALSE가 나왔습니다.

VARCHAR나 VARCHAR2 같은 경우에는 우선 같다고 보고 CHAR와 VARCHAR를 비교해서 설명해드리겠습니다.

 

CHAR 같은경우에는 4byte로 공간을 잡았는데, 문자가 4byte가 다 안채워지면 나머지가 공백으로 채워지도록 되어 있습니다.

그렇기 때문에 나는 분명히 A 라는 문자를 넣었는데, 자동적으로 'A∨∨∨' 가 되어 공백을 집어넣어야 TRUE 가 되는 것을 볼 수 있습니다.

이런 의미로 고정형이라는 말이 쓰이는 것입니다. 왜냐면 공백이 채워지지 않게 하기위에선 할당한 공간을 꽉채워야 하기 때문입니다.

예를들어 형식을 정한 날짜라던지 주민등록번호 처럼 절대 글자수가 변화가 되지 않는 경우에 사용하면 적당하다고 볼 수 있습니다.

(하지만 일반적으로는 VARCHAR로 공백을 생각치 않고 쓰는 경우가 많은것 같습니다.)

 

반면 VARCHAR는 4byte를 할당하고 'A'라는 1byte의 문자를 입력하면 CHAR와는 다르게 공백이 채워지는것이 아니라 입력한 부분만 쓰입니다.

이런 의미로 가변형이라는 말이 쓰이는 것입니다. 왜냐면 할당한 영역은 4byte 지만 나는 꼭 4byte를 쓰지 않고 매번 다를 수도 있기 때문입니다.

예를들어 아이디라는 컬럼이 있으면 그 컬럼은 매번 다른 수의 글자가 입력이 될 것입니다. 그럼에도 공백이 채워지지 않기에,

걱정없이 컬럼을 사용 할 수가 있으니 글자수의 변화가 있는 경우에 사용하면 적당하다고 볼 수 있습니다.

아 그리고, 반대로 'A'문자를 비교했을때를 궁금해하실 수 있으니 보고 가겠습니다.

 

SELECT  DECODE(T_CHAR, 'A', 'TRUE', 'FALSE')         T_CHAR,
           DECODE(T_VARCHAR, 'A', 'TRUE', 'FALSE')    T_VARCHAR,
           DECODE(T_VARCHAR2, 'A', 'TRUE', 'FALSE')  T_VARCHAR2
FROM  TEST_CHARACTER; 

 

위와 같이 셀렉트를 하면 아래와 같은 결과가 나옵니다.

 

 

결과는, 반대로 CHAR만 FALSE가 나오는 것을 볼 수 있습니다.

그러니까, CHAR형태로 컬럼을 만들고 할당 영역을 꽉채우는 데이터가 아니라면, 내가 넣었을땐 'A'라는 문자를 입력했더라도, 조건으로 아무리 비교해봐야 내가 원하는 결과가 나올 수가 없다는 것입니다.

 

다음으로 위에 적혀있는 BYTE수는 데이터 길이 제한의미합니다. (CHAR : 2000byte / VARCHAR, VARCHAR2 : 4000byte)

그리고 VARCHAR와 VARCHAR2 같은경우에는 현재는 차이가 없으나, 오라클쪽에서 추후에 VARCHAR 같은경우에는 다른 형태로 쓰일 수 있다고 합니다.

그렇기 때문에 오라클에서는 VARCHAR보다는 VARCHAR2를 쓰는것을 권장한다고 합니다.

(이 내용은 Oracle10g 어느 문서에 적혀있다고 합니다...)

 

 

그래서 최종결론은!!!

 

§ CHAR는 문자의 길이가 고정적일때 사용하고!!!

§ VARCHAR는 문자의 길이가 변화가 있을때 사용하고!!!

§ 오라클에서는 VARCHAR보다 VARCHAR2를 쓰는 것을 권장한다!!!

 

 

※ 아 참고로... 오라클 기준에 설명 드렸습니다.. 다른 DB도 어느정도 일치하나.. 그렇다고 또 완전히 디테일하게 맞지는 않으니.. 참고하시기 바랍니다..ㅎ

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

오라클의 EXISTS와 IN함수는 의미는 거의 비슷하지만 조금의 차이를 가진다.

(NOT은 각 함수의 반대의 의미를 가진다)

 

간단하게 보면, 둘다 존재하느냐 포함하느냐 머 비슷하다.

하지만 사용 방식의 차이와 NULL 값을 포함하냐 마느냐 차이가 있다.

그리고 EXISTS는 서브쿼리만을 사용이 가능하고, IN은 서브쿼리뿐만 아니라 단순 값도 사용이 가능하다.

이런 설명보단 예시로 보는게 가장 이해하기 좋은 것 같으니 예시를 봐보자.

 

(가로로 배치했었는데... 반응형때문에.. 뭉개져서.. 보시기 불편하겠지만.. 세로로 했습니다.ㅠ,ㅠ)

 

     

    <TEST_IN_AND_EXISTS >              

 

 

    <TEST_IN_AND_EXISTS2>

 

우선 두 테이블에 위와 같이 데이터를 넣어놨다.

저같은경우에는 IN만 알고 있었는데, EXISTS라는 것을 알게되 비교 포스팅을 하게 되었습니다.

처음에는.. EXISTS가 잘 이해 안됬었는데.. 현재도 완전 디테일하게는 이해를 못했지만.. 이렇게 생각하자라고 결론을 냈습니다.

먼저 EXISTS 쿼리 부터 보면,

 

SELECT A.B_COLUMN, A.A_COLUMN
FROM TEST_IN_AND_EXISTS A
WHERE EXISTS (SELECT B.A_COLUMN FROM TEST_IN_AND_EXISTS2 B WHERE B.A_COLUMN = A.B_COLUMN);

 

제가 이해가 잘 안된부분은 서브쿼리였는데..

(사실.. 저 서브쿼리가 멀 나타내주는지를 정확히는 이해를 못한 상태입니다..)

단순하게 생각하면 두테이블을 비교하는데 조건을 A 테이블의 B_COLUMN과 B 테이블의 A_COLUMN을 기준이라고 보면 된다..

(TEST_IN_AND_EXISTS의 Alias를 A 2를 B로 했기에 A 테이블과 B 테이블로 부르겠습니다..)

좀 더 쉽게 말하면 B 테이블의 A_COLUMN의 값이 A 테이블의 B_COLUMN에 존재하는 데이터를 불러와줘 라고 보면 된다..

말로만 하지말고 결과를 보면,

 

 

위와 같은 결과를 볼 수 있는데,

예시를 다시 말로 풀어보면, B테이블의 A_COLUMN의 값은 1,2,3,4,5,6,7 이 있다. 이 값이 존재하는 A테이블의 B_COLUMN의 값중에 존재하는 값들만 보여줘라는 쿼리구문이다. 그래서 A테이블의 B_COLUMN이 1,2,3인 것은 보여주고 9와 null 값은 포함하지 않기에 보여주지 않는 것이다.

이상태에서 IN 쿼리를 비교해 보면,

 

SELECT A.B_COLUMN, A.A_COLUMN
FROM TEST_IN_AND_EXISTS A
WHERE A.B_COLUMN IN (SELECT B.A_COLUMN FROM TEST_IN_AND_EXISTS2 B); 

 

같은 의미를 지닐수 있도록 IN함수로 쿼리를 표현해봤습니다.

EXISTS와 달리 IN함수 같은경우에는 비교할 컬럼을 앞에 넣어 줍니다.

(그래서 처음에 EXISTS는 머랑 비교 하는거지 라는 것에 고민을 많이 햇었습니다...)

위 쿼리를 말로 해보면 A테이블의 A.B_COLUMN 값 중에 B테이블의 B.A_COLUMN들이 포함한 데이터를 불러와줘 이다..

결과를 보면,

 

 

EXISTS와 별차이가 없는 것을 볼 수 있다.

근데 왜 EXISTS와 IN을 비교해놨어라고 할 수 있지만, NOT이 포함한 함수에서 위에서도 잠깐 언급한 차이를 볼 수 있다.

NOT EXISTS 쿼리로 보면,

 

SELECT A.B_COLUMN, A.A_COLUMN
FROM TEST_IN_AND_EXISTS A
WHERE NOT EXISTS (SELECT B.A_COLUMN FROM TEST_IN_AND_EXISTS2 B WHERE B.A_COLUMN = A.B_COLUMN); 

 

EXISTS쿼리 의미에서 NOT 이 붙음으로써 딱 반대되는 의미이다.

그렇기에 바로 결과를 보면,

 

 

말그대로 딱 정반대의 A테이블의 나머지 3개의 데이터를 가진 결과가 나온다. NULL값을 포함한..

그다음 NOT IN 쿼리를 보면,

 

SELECT A.B_COLUMN, A.A_COLUMN
FROM TEST_IN_AND_EXISTS A
WHERE A.B_COLUMN NOT IN (SELECT B.A_COLUMN FROM TEST_IN_AND_EXISTS2 B);

 

IN쿼리 의미에서 NOT 이 붙음으로써 딱 반대되는 의미이다.

그렇기에 바로 결과를 보면,

 

 

이 건 말그대로 정반대 같지만, NULL 값이 포함되어있지 않는다.!!!

그래서 NOT이 포함한 함수를 쓸대는 이 점을 잘 고려해서 사용해야 한다!!

이 점을 생각하지 못하고 NOT IN을 쓰고 NOT EXISTS를 사용했다가는 큰 혼란이 올 수 있으니, 이번에 꼭 알아가도록 합시다!ㅎ

 

아 추가적으로,

위에서 IN 함수 같은경우에는 서브쿼리가 아닌 단순 값으로도 가능하다 했었는데, 잠깐만 보고 가자.

쿼리로 보면,

 

SELECT A.B_COLUMN, A.A_COLUMN
FROM TEST_IN_AND_EXISTS A
WHERE A.B_COLUMN IN ('1', '2');

 

SELECT A.B_COLUMN, A.A_COLUMN
FROM TEST_IN_AND_EXISTS A
WHERE A.B_COLUMN NOT IN ('1', '2');

 

위와 같이 서브쿼리 대신 단순 값으로 사용 할 수 있고,

결과를 보면,

 

          

              <IN 함수>      

 

                            

          <NOT IN 함수>

 

IN 함수에서는 1,2 값을 포함한 결과값을 볼 수 있고, NOT IN 함수에서는 NULL값을 포함하지 않고 1,2 값을 포함하지 않은 결과 값을 볼 수 있게 된다.

 

저 같은 경우에는 IN, NOT IN 만을 썼었는데,

EXISTS와 NOT EXISTS을 알게 되면서 다른 분들도 같이 알면 좋겠다는 생각이 들어 포스팅을 하게되었습니다.

 

이 글을 보시는 분들 중에 두가지 중에 한가지만 알거나 하나도 모르거나 먼가 빠트린 점이 있으셨던 분들에게 도움이 되셨기를 바랍니다!ㅎ

 

(아! 그리고 혹시나 제가 잘못 이해 하고 있는 점이 있으면.. 조언 부탁드리겠습니다!)

 

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

  Windows10을 쓰시는 분이 sqldeveloper 를 다운 받고 쓰려고, java path를 입력 하고, 사용하려면 이러한 에러가 발생할 것이다!!! 아마도...

 



당황하지 말고, JDK를 설치한경로로 가서, jre > bin 폴더로 이동하여 msvcr100.dll 을 복사하여

C:\Windows\System32 에 붙여넣기 하고 다시 실행을 하면 잘 되는 것을 확인 할 수 있다!!


336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.



org.apache.ibatis.exceptions.TooManyResultsException:

Expected one result (or null) to be returned by selectOne(), but found: 2


정해져있는 반환값이 1개인데, 지금 받아오는 값의 개수가 만족하지 않아

발생하는 에러입니다!!

지금 같은 경우에는 정해져있는 반환값은 1개인데,

실제로 반환 되는 값이 2개라 에러가 발생했습니다.


보시다시피 xml에 반환값은 인트 한개인데, Select를 해본 결과 값이 2개인 것을 알수있습니다.

말 그대로 닮을 수 있는 그릇은 한개인데, 그 이상이 들어오다니보니 TooManyResult라는 Exception이 발생하게 되는것이다!


'DB' 카테고리의 다른 글

[Oracle] CHAR, VARCHAR, VARCHAR2  (2) 2017.08.21
[Oracle] EXISTS, NOT EXISTS, IN, NOT IN  (14) 2017.08.17
[Oracle] Windows10 sqldeveloper jvm.dll error  (0) 2017.02.23

+ Recent posts