프린트 하기

OS환경 : Oracle Linux 7.6 (64bit)

 

DB 환경 : Oracle Database 19.10.0.0

 

방법 : 오라클 19c 소문자 컬럼 테스트

테스트 중 신기한 점을 발견함

create table 명령을 이용해 테이블 생성시

1
SQL> create table lowertest as select object_name "col1" from dba_objects;

이렇게 ""을 이용해서 테이블을 만들면 컬럼명이 소문자로 만들어짐

 

 

일반적으론 아래와 같이 생성할 시 lowertest 테이블의 col1 컬럼은 자동으로 대문자로 만들어짐

1
SQL> create table lowertest2 as select object_name col1 from dba_objects;

 

 

테이블 구조 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
SQL> desc lowertest
 
 Name     Null?    Type
 ------  ------    -----
 col1              VARCHAR2(128)
(col1 소문자)
 
SQL> desc lowertest2
 
 Name     Null?    Type
 ------  ------    -----
 COL1              VARCHAR2(128)
(COL1 대문자)

 

 

추가 테스트

컬럼 대소문자 섞어서 테이블 재생성

1
2
3
SQL>
drop table lowertest purge;
create table lowertest (col1 number, "col2" number, col3 varchar2(5), "col4" varchar2(5));

 

 

insert 시 컬럼 나열 없이 샘플 데이터 삽입

1
2
3
SQL> insert into lowertest values (12'3''4');
 
1 row created.

정상적으로 삽입됨

 

 

insert 시 컬럼 나열 후 샘플 데이터 삽입

1
2
3
4
SQL> insert into lowertest (col1, col2, col3, col4values (12'3''4');
                                         *
ERROR at line 1:
ORA-00904"COL4": invalid identifier

에러 발생함

 

 

컬럼명 "" 를 이용해 소문자로 설정 후 삽입

1
2
3
4
SQL> insert into lowertest (col1, "col2", col3, "col4"values (12'3''4');
 
1 row created.
commit;

정상적으로 삽입됨

 

 

테이블 구조 확인

1
2
3
4
5
6
7
SQL> desc lowertest
 Name      Null?    Type
 ------ -------- -----------
 COL1              NUMBER
 col2              NUMBER  <-- 소문자
 COL3              VARCHAR2(5)
 col4              VARCHAR2(5)  <-- 소문자

 

 

select * 로 테이블 조회

1
2
3
4
5
6
SQL> select * from lowertest;
 
      COL1       col2 COL3  col4
---------- ---------- ----- -----
         1          2 3     4
         1          2 3     4

col2, col4 소문자임

 

 

select 시 소문자만 사용해서 조회

1
2
3
4
SQL> select col1, col2, col3, col4 from lowertest;
                         *
ERROR at line 1:
ORA-00904"COL4": invalid identifier

에러 발생함

 

 

select 시 컬럼명에 "" 사용해서 조회

1
2
3
4
5
6
SQL> select col1, "col2", col3, "col4" from lowertest;
 
      COL1       col2 COL3  col4
---------- ---------- ----- -----
         1          2 3     4
         1          2 3     4

정상적으로 조회됨

col2, col4 은 소문자임

 

 

여기서 다시 ""을 이용해 alias 로 조회하면 모두 대문자로 조회됨

1
2
3
4
5
6
SQL> select col1, "col2" "COL2", col3, "col4" "COL4" from lowertest;
 
      COL1       COL2 COL3  COL4
---------- ---------- ----- -----
         1          2 3     4
         1          2 3     4

alias를 써서 대문자로 만들어주면 모두 대문자로 나옴

 

 

where 절 역시 ""을 넣지 않으면 에러 발생함

1
2
3
4
5
SQL> select * from lowertest
where col2 = 2;
      *
ERROR at line 2:
ORA-00904"COL2": invalid identifier

 

 

"" 사용시 정상적으로 조회됨

1
2
3
4
5
6
7
SQL> select * from lowertest
where "col2" = 2;
 
      COL1       col2 COL3  col4
---------- ---------- ----- -----
         1          2 3     4
         1          2 3     4

 

 

인덱스 생성시에도 마찬가지로 에러 발생함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
SQL>
create index lowertest_ix1 on lowertest(col1);
 
Index created.
(정상) 
 
create index lowertest_ix2 on lowertest(col2);
                                        *
ERROR at line 1:
ORA-00904"COL2": invalid identifier
(에러 발생) 
 
create index lowertest_ix2 on lowertest("col2");
 
Index created.
(정상)
 
create index lowertest_ix3 on lowertest(col3);
 
Index created.
(정상)
 
create index lowertest_ix4 on lowertest(col4);
                                        *
ERROR at line 1:
ORA-00904"COL4": invalid identifier
(에러 발생) 
 
create index lowertest_ix4 on lowertest("col4");
 
Index created.
(정상)

 

 

해당 테이블 쿼리 플랜 확인

statistics_level 파라미터 세션레벨에서 all로 변경

1
2
3
SQL> alter session set statistics_level = all;
 
Session altered.

 

 

테이블 조회1

1
2
3
4
5
6
SQL> select * from lowertest where col1 = 1;
 
      COL1      col2 COL3  col4
---------- ---------- ----- -----
         1          2 a     b
         1          2 a     b

 

 

xplan display_cursor 조회 테이블 조회1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULLNULL'ADVANCED ALLSTATS LAST'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  1nv7xbyf8pnfn, child number 1
-------------------------------------
select * from lowertest where col1 = 1
 
Plan hash value: 2424170803
 
-----------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name          | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |               |      1 |        |       |     2 (100)|          |      2 |00:00:00.01 |       4 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| LOWERTEST     |      1 |      2 |    68 |     2   (0)| 00:00:01 |      2 |00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN                  | LOWERTEST_IX1 |      1 |      2 |       |     1   (0)| 00:00:01 |      2 |00:00:00.01 |       2 |
-----------------------------------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / LOWERTEST@SEL$1
   2 - SEL$1 / LOWERTEST@SEL$1
 
Outline Data
-------------
 
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('19.1.0')
      DB_VERSION('19.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX_RS_ASC(@"SEL$1" "LOWERTEST"@"SEL$1" ("LOWERTEST"."COL1"))
      BATCH_TABLE_ACCESS_BY_ROWID(@"SEL$1" "LOWERTEST"@"SEL$1")
      END_OUTLINE_DATA
  */
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("COL1"=1)
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - "COL1"[NUMBER,22], "LOWERTEST"."col2"[NUMBER,22], "LOWERTEST"."COL3"[VARCHAR2,5], "LOWERTEST"."col4"[VARCHAR2,5]
   2 - "LOWERTEST".ROWID[ROWID,10], "COL1"[NUMBER,22]
 
Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
 
Query Block Registry:
---------------------
 
  <q o="2" f="y"><n><![CDATA[SEL$1]]></n><f><h><t><![CDATA[LOWERTEST]]></t><s><![CDATA[SEL$1]]></s></h></f></q>
 
 
 
56 rows selected.

43번 째 줄에서 보면 자동으로 col1 컬럼을 ""을 이용해서 대문자로 변경해서 조회함

 

 

테이블 조회2

1
2
3
4
5
6
SQL> select * from lowertest where "col2" = 2;
 
      COL1       col2 COL3  col4
---------- ---------- ----- -----
         1          2 a     b
         1          2 a     b

 

 

xplan display_cursor 조회2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULLNULL'ADVANCED ALLSTATS LAST'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  akzxu3usspmy4, child number 0
-------------------------------------
select * from lowertest where "col2" = 2
 
Plan hash value: 4099624448
 
-----------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name          | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |               |      1 |        |       |     2 (100)|          |      2 |00:00:00.01 |       4 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| LOWERTEST     |      1 |      2 |    68 |     2   (0)| 00:00:01 |      2 |00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN                  | LOWERTEST_IX2 |      1 |      2 |       |     1   (0)| 00:00:01 |      2 |00:00:00.01 |       2 |
-----------------------------------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / LOWERTEST@SEL$1
   2 - SEL$1 / LOWERTEST@SEL$1
 
Outline Data
-------------
 
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('19.1.0')
      DB_VERSION('19.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX_RS_ASC(@"SEL$1" "LOWERTEST"@"SEL$1" ("LOWERTEST"."col2"))
      BATCH_TABLE_ACCESS_BY_ROWID(@"SEL$1" "LOWERTEST"@"SEL$1")
      END_OUTLINE_DATA
  */
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("col2"=2)
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - "LOWERTEST"."COL1"[NUMBER,22], "col2"[NUMBER,22], "LOWERTEST"."COL3"[VARCHAR2,5], "LOWERTEST"."col4"[VARCHAR2,5]
   2 - "LOWERTEST".ROWID[ROWID,10], "col2"[NUMBER,22]
 
Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
 
Query Block Registry:
---------------------
 
  <q o="2" f="y"><n><![CDATA[SEL$1]]></n><f><h><t><![CDATA[LOWERTEST]]></t><s><![CDATA[SEL$1]]></s></h></f></q>
 
 
 
56 rows selected.

43번 째 줄에서 보면 where 절에 작성한것처럼 col2 컬럼을 ""을 이용해서 소문자로 조회함

 

 

테이블 조회(문자형 컬럼인 col3을 숫자형으로 조회)

1
2
3
4
5
6
SQL> select * from lowertest where col3 = 3;
 
      COL1       col2 COL3  col4
---------- ---------- ----- -----
         1          2 3     4
         1          2 3     4

 

 

xplan display_cursor 조회3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULLNULL'ADVANCED ALLSTATS LAST'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  0f47vxcpjjwk0, child number 0
-------------------------------------
select * from lowertest where col3 = 3
 
Plan hash value: 597123558
 
-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name      | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |      1 |        |       |     3 (100)|          |      2 |00:00:00.01 |       8 |
|*  1 |  TABLE ACCESS FULL| LOWERTEST |      1 |      2 |    68 |     3   (0)| 00:00:01 |      2 |00:00:00.01 |       8 |
-------------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / LOWERTEST@SEL$1
 
Outline Data
-------------
 
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('19.1.0')
      DB_VERSION('19.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "LOWERTEST"@"SEL$1")
      END_OUTLINE_DATA
  */
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter(TO_NUMBER("COL3")=3)
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - "LOWERTEST"."COL1"[NUMBER,22], "LOWERTEST"."col2"[NUMBER,22], "COL3"[VARCHAR2,5],
       "LOWERTEST"."col4"[VARCHAR2,5]
 
Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
 
Query Block Registry:
---------------------
 
  <q o="2" f="y"><n><![CDATA[SEL$1]]></n><f><h><t><![CDATA[LOWERTEST]]></t><s><![CDATA[SEL$1]]></s></h></f></q>
 
 
 
53 rows selected.

40번 쨰 줄에 보면 자동으로 형변환이 되고 to_number안에 col3가 자동으로 "" 처리 되어서 대문자로 나옴

 

 

테이블 조회(문자형 컬럼인 "col4"을 숫자형으로 조회)

1
2
3
4
5
6
SQL> select * from lowertest where "col4" = 4;
 
      COL1       col2 COL3  col4
---------- ---------- ----- -----
         1          2 3     4
         1          2 3     4

 

 

xplan display_cursor 조회4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULLNULL'ADVANCED ALLSTATS LAST'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  2syvzqtdutd3c, child number 0
-------------------------------------
select * from lowertest where "col4" = 4
 
Plan hash value: 597123558
 
-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name      | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |      1 |        |       |     3 (100)|          |      2 |00:00:00.01 |       8 |
|*  1 |  TABLE ACCESS FULL| LOWERTEST |      1 |      2 |    68 |     3   (0)| 00:00:01 |      2 |00:00:00.01 |       8 |
-------------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / LOWERTEST@SEL$1
 
Outline Data
-------------
 
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('19.1.0')
      DB_VERSION('19.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "LOWERTEST"@"SEL$1")
      END_OUTLINE_DATA
  */
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter(TO_NUMBER("col4")=4)
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - "LOWERTEST"."COL1"[NUMBER,22], "LOWERTEST"."col2"[NUMBER,22], "LOWERTEST"."COL3"[VARCHAR2,5],
       "col4"[VARCHAR2,5]
 
Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
 
Query Block Registry:
---------------------
 
  <q o="2" f="y"><n><![CDATA[SEL$1]]></n><f><h><t><![CDATA[LOWERTEST]]></t><s><![CDATA[SEL$1]]></s></h></f></q>
 
 
 
53 rows selected.

40번 쨰 줄에 보면 자동으로 형변환이 되고 to_number안에 col3가 where 에서 작성한대로 "" 처리 되어서 소문자로 나옴

 

 

결론 : 

오라클에서 테이블 생성 시 자동로 대분자 컬럼으로 만들어짐

굳이 ""를 이용해 소문자로 만들면 쿼리 사용시 불편함

xplan 상에서 보면 자동으로 해당 컬럼 소문자, 대문자 상관없이 모두 ""가 들어감

하지만 datapump expdp나 impdp 시 job name을 소문자로 쓰면 소문자 object 로 만들어짐

이 경우 https://positivemh.tistory.com/902 내용처럼 job이 비정상 중단된 경우 ""를 이용해서 지워줘야하기 때문에

대문자를 사용하는게 좋아보임

 

 

참조 : 

https://positivemh.tistory.com/902