본문 바로가기
프로그래밍 놀이터/Database

[SQLite3] 03. SQL 고급 #2

by 돼지왕왕돼지 2018. 5. 19.
반응형

[SQLite3] 03. SQL 고급 #2



이 글은 "빠르게 활용하는 모바일 데이터베이스 SQLite3” 이란 글을 보며 필요한 내용만 정리한 글입니다.

자세한 내용은 책을 구매해서 보세요

Acid, ADD, after, alter table, atomic action, atomicity, Attach, attach database, autocommit, autocommit 모드, Before, Begin, begin deffered, begin exclusive, begin immediate, BLOB, Cast, COMMIT, consistency, create trigger, default, Delete, detach database, durability, dynamic data type, exclusive, for each row, for each statement, index, insert, instead of, integer, ISOLATION, journal file, locking state, Memory DB, memory:, new, NOT NULL, Numeric, of, Old, pending, Primary Key, Real, release savepoint, rename to, reserved, rollback, rollback to savepoint, savepoint, shared, sql 고급, SQLite, sqlite boolean, SQLITE3, sqlite3_open, sqlite_busy, sqlite_max_attached, Stack, static data type, Storage Class, syntax, text, transaction, transaction stack, trigger, trigger for specific column, trigger of, trigger on specific condition, trigger timing, trigger when, triggeroperation, type affinity, unique, unlocked, Update, utf-8, View, 고립성, 다른 db 파일 연결, 동적 자료형, 수정 가능한 뷰, 스토리지 클래스, 원자성, 유닉스 시간, 일관성, 저널 파일, 줄리안 날짜, 중첩된 트랜잭션, 지속성, 칼럼 추가, 컬럼 추가, 타입 선호도, 테이블 수정, 트랜잭션, 트랜잭션 구문, 트랜잭션 스택, 트리거


9. 트리거


-

DB TRIGGER 란 특정 테이블이나 뷰에 INSERT, DELETE, UPDATE 와 같은 데이터 조작 이벤트가 발생했을 때 자동으로 지정된 동작을 수행하게 하는 것이다.



트리거 활용


-

syntax

CREATE TRIGGER [triggerName] [triggerTiming] [triggerOperation] ON [tableName]

BEGIN

    [sqlOperations]

END;


triggerTiming 은 아래와 같다.

BEFORE : 대상 테이블의 CUD 동작 직전에 트리거에서 지정한 동작이 수행된다.

AFTER : 대상 테이블의 CUD 동작 완료 후 트리거에서 지정한 동작이 수행된다.

INSTEAD OF : 대상 테이블의 CUD 동작 대신 지정된 동작이 수행된다.


triggerOperation INSERT, DELETE, UPDATE 중 하나이다.



-

sqlOperations 에서는 NEW, OLD 키워드로 테이블을 참조할 수 있다.

NEW 는 operation 이 완료된 후의 레코드의 해당 컬럼 값을 의미하고, OLD 는 operation 이 수행되기 전의 컬럼 값을 나타낸다.

INSERT 의 경우 새롭게 입력되는 데이터만 존재하므로 NEW 만 사용하고, DELETE 문의 경우 반대로 OLD 만 사용 가능하다.

UPDATE 는 NEW, OLD 모두 사용 가능하다.


ex) INSERT operation 이 있을 때마다 log 를 쌓음

CREATE TRIGGER tr_BookInfo_Insert

    BEFORE INSERT ON bookInfo

    BEGIN

        INSERT INTO bookInfoLog(operation, title, after_price) VALUES(‘INSERT’, NEW.title, NEW.price);

    END;



FOR EACH ROW 와 FOR EACH STATEMENT


-

트리거 동작 방식 가운데 FOR EACH ROW 방식은 테이블에서 변경되는 각 행(row)에 대해 트리거가 수행되는 것을 의미한다.

예를 들어 UPDATE 나 DELETE 구문의 경우 하나의 SQL 문장으로 테이블에서 여러 행의 데이터가 변경될 수 있다.

이 때 FOR EACH ROW 방식으로 트리거가 수행되면 변경되는 행마다 트리거가 동작한다.


ex) Delete 되는 row 들을 모두 log 에 쌓음

CREATE TRIGGER tr_BookInfo_Delete

    AFTER DELETE ON bookInfo

    FOR EACH ROW

    BEGIN

        INSERT INTO bookInfoLog(op, title, bf_price) VALUES(‘DELETE’, OLD.title, OLD.price);

    END;


이와 다르게 변경된 행의 개수에 상관없이 오직 한 번만 수행되는 트리거 방식을 FOR EACH STATEMENT 라고 한다.

SQLite3 에서는 현재 FOR EACH ROW 방식만 지원하므로 FOR EACH ROW 를 명시하지 않아도 된다.



-

UPDATE 구문의 경우 특정 칼럼이 갱신되는 경우에만 트리거가 실행되도록 할 수 있다.

OF [tableName] ON [columnName] 으로 모니터링할 컬럼을 설정할 수 있다.


CREATE TRIGGER tr_BookInfo_Update_Price

    AFTER UPDATE OF price ON bookInfo

    BEGIN

        …

    END;



특정 조건에만 동작하는 트리거


트리거를 생성할 때 WHEN 절을 사용해서 특정 조건을 만족하는 경우에만 트리거가 수행되게 할 수 있다.


ex) publisher_id 가 1인 레코드를 삭제하는 경우에만 trigger 되도록 함.

CREATE TRIGGER tr_BookInfo_Delete_Wikibooks

    AFTER DELETE ON bookInfo

    WHEN OLD.publisher_id = 1

    BEGIN

        …

    END;


WHEN 조건절은 WHERE 조건절과 동일하며, 이때도 대상 테이블이 컬럼값에 접근하기 위해서는 OLD 나 NEW 키워드를 사용해야 한다.



수정 가능한 뷰


뷰는 읽기 전용이므로 뷰를 대상으로 CUD 를 수행하면 에러가 발생한다.

이런 경우 INSTEAD OF 트리거를 리용해서 수정가능한 뷰처럼 동작하게 할 수 있다.


CREATE TRIGGER tr_vwPrettyBookInfo_Update

    INSTEAD OF UPDATE ON vwPrettyBookInfo

    BEGIN

        …

    END;




10. 테이블 수정


-

ALTER TABLE 구문을 이용하면 이미 생성된 테이블을 수정할 수 있다.

하지만 SQLite3 에서는 RENAME TO 와 ADD 연산만 지원한다.



테이블 이름 변경


syntax

ALTER TABLE [tableName] RENAME TO [newTableName];


테이블에 인덱스가 존재하는 경우 테이블 이름을 변경하면 특별한 작업 없이 인덱스가 정의되어 있는 테이블 이름도 함께 변경된다.


하지만 변경된 테이블을 참조하는 뷰, 트리거의 경우에는 ALTER TABLE 구문으로 자동으로 수정되지 않는다. 이러한 경우 해당 뷰, 트리거를 삭제하고 다시 생성해야 한다.



컬럼 추가


syntax

ALTER TABLE [tableName] ADD [addingColumnName] [type];


추가되는 컬럼에는 PRIMARY KEY, UNIQUE 제약조건을 설정할 수 없지만 기본값(DEFAULT)은 설정할 수 있다. 또한 NOT NULL 제약조건만은 안 되고 이를 설정하려면 DEFAULT 도 함께 설정해야만 한다.




11. 트랜잭션


-

서로 분리할 수 없는 동작을 원자적 행위(atomic action)라고 한다.

DB 에서는 이러한 트랜잭션(transaction)이라는 개념을 적용해서 일련의 SQL 작업이 완전히 모두 수행되거나 모두 수행되지 않게 해서 무결성(integrity)를 유지한다.

이런 이유로 transaction 은 db 의 논리적 작업 단위(LUW, Logical Units of Work)라고 한다.



트랜잭션 구문


-

SQLite3 에서 명시적으로 트랜잭션을 사용하기 위해서는 BEGIN 명령어를 사용한다.

BEGIN 이후에 나오는 SQL 문들은 정상적으로 수행돼도 프로세스의 메모리상에서만 반영되며, 실제 DB 파일에는 반영된 상태가 아니다.

이 상태에서 해당 프로세스가 비정상적으로 종료되거나 전원 시스템이 차단되어 OS 가 종료되면 그때까지 수행된 내용은 DB 파일에 반영되지 않는다.

COMMIT 명령어는 Transaction 이 시작된 이후로 수행된 모든 SQL 연산을 물리적인 DB 파일에 반영한다.

반대로 ROLLBACK 명령어는 Transaction 이 시작된 이후로 수행된 모든 연산을 취소하고, DB 를 Transaction 이 시작된 시점으로 복원한다.



-

하나의 Transaction 안에서는 다수의 SQL 문을 수행할 수 있으며, 하나 이상의 테이블, ATTACH 된 다른 데이터베이스 파일에 대해서도 원자적으로 여러 SQL 문을 수행할 수 있다.



AUTOCOMMIT 모드


-

명시적으로 BEGIN 으로 시작해서 COMMIT/ROLLBACK 명령어로 Transaction 을 종료하지 않더라도 SQLite3 내부에서 DB 를 변경하는 모든 SQL 문은 하나의 Transaction 내에서 수행된다.

예를 들어 하나의 INSERT 문을 실행하더라도 SQLite3 에서는 내부적으로 Transaction 을 시작하고. INSERT 문을 수행한다. 이 경우 SQL 구문이 정상적으로 수행되면 자동으로 COMMIT 되며 실패하는 경우 ROLLBACK 된다.

이렇게 동작하는 방식을 AUTOCOMMIT 모드라 하며, SQLite3 는 명시적으로 트랜잭션을 시작하지 않는 경우에는 기본적으로 AUTOCOMMIT 모드로 동작한다.



-

ACID 는 DB 에서 하나의 Transaction 이 안전하게 수행되기 위해 필요한 특성으로 Atomicity(원자성), Consistency(일관성), Isolation(고립성), Durability(지속성) 을 이야기한다.



중첩된 트랜잭션


-

SQLite3 에서 BEGIN 구문을 사용한 트랜잭션을 중첩하면 에러가 발생한다.

하지만 SAVEPOINT 명령어를 사용하면 중첩된 트랜잭션을 생성할 수 있으며, 각 트랙잭션마다 별칭을 부여하고 롤백 시에도 해당 별칭의 위치로 복원할 수 있다.



-

syntax

SAVEPOINT [alias]


SAVEPOINT 명령어는 BEGIN 과 COMMIT 명령어 사이에서 사용되거나, BEGIN 없이 단독으로 사용되어 트랜잭션을 시작할 수 있다.

이 때 BEGIN 없이 SAVEPOINT 를 단독으로 사용하는 경우 첫 SAVEPOINT 문장은 BEGIN DEFERRED TRANSACTION 과 같은 동작을 수행한다.

여기서 DEFERRED 란 DB 파일에 대한 잠금 수준(Lock Level)을 명시적으로 결정하는 구문이다.



-

하나의 트랜잭션 내에서 둘 이상의 SAVEPOINT 가 호출되는 경우 SQLite3 의 내부적인 동작 방식은 Stack 과 같이 동작하며, SQLite3 공식 문서에는 이를 트랜잭션 스택이라고 한다.(Transaction Stack)

즉, SAVEPOINT 구문은 시간에 따라 진행되는 트랜잭션 연산에서 각 시점의 표식(mark)라고 생각하면 된다.



-

ROLLBACK TO SAVEPOINT [alias]


ROLLBACK TO SAVEPOINT 명령어는 수행 중인 트랜잭션을 앞서 표시해둔 해당 [alias] 의 위치로 복원한다.

BEGIN 구문을 이용해서 명시적으로 트랜잭션을 시작했거나 전체 트랜잭션 스택 내에 SAVEPOINT 로 생성한 또 다른 트랜잭션이 존재하는 경우에는 전체 트랜잭션은 종료되지 않는다.

만약 [alias] 없이 ROLLBACK 만 사용하는 경우 트랜잭션 스택의 모든 트랜잭션이 복원된다.



-

RELEASE SAVEPOINT [alias]


RELEASE SAVEPOINT 명령어는 기본적으로 해당 [alias] 의 트랜잭션을 DB 에 반영한다.

하지만 트랜잭션 스택 내에 SAVEPOINT 로 생성한 모든 트랜잭션이 RELEASE 명령어로 반영되거나 명시적으로 COMMIT 명령어를 사용하지 않은 경우에는 실제 DB 파일은 수정하지 않고 프로세스의 내부 메모리상에서만 반영된다.

따라서 RELEASE SAVEPOINT 를 수행한 이후 ROLLBACK TO SAVEPOINT 명령어로 해당 위치보다 더 앞선 시점으로 이동하거나, 비정상적으로 해당 프로세스가 종료될 때는 RELEASE SAVEPOINT 로 커밋한 내용이라도 DB 파일에 반영되지 않는다.

또한 ROLLBACK TO SAVEPOINT 명령어와 동일하게 트랜잭션 스택의 가장 꼭대기(top)에 있는 트랜잭션이 릴리스(RELEASE)되면 그 사이에 진행된 모든 트랜잭션은 DB 파일에 반영된다.



-

ROLLBACK TO SAVEPOINT 나 RELEASE SAVEPOINT 를 수행하면 해당 savePoint 도 Stack 에서 제거된다.



-

SQLite3 은 하나의 DB 파일을 둘 이상의 프로세스에서 공유해서 읽고 쓸 수 있다.

이때 해당 프로세스에서 DB 파일을 읽거나 수정하려면 적절한 Lock 을 획득해야 하는데, 그렇지 못한 경우 종종 SQLITE_BUSY 에러가 발생하기도 한다.


SQLite3 을 사용하는 프로세스 관점에서 DB 파일은 다음의 locking states 중 하나에 속하게 된다.


UNLOCKED : 언제라도 다른 프로세스에서 읽기/쓰기 가능한 상태

SHARED : 프로세스에서 읽기를 하는 상태로 이 때 다른 프로세스에서 동시 읽기는 가능. 다른 프로세스에서 쓰기는 불가능

RESERVED : 미래의 어느 시점에 DB 에 쓰기를 할 예정인 상태로, 이때도 다른 프로세스들은 읽기를 할 수 있다. (SHARED LOCK 획득 가능). 하지만 시스템 전체에서 오직 한 프로세스만이 RESERVED LOCK 을 가질 수 있다.

PENDING : EXCLUSIVE LOCK 을 얻기 직전의 임시적인 상태로, 다른 프로세스의 SHARED LOCK 이 모두 해제될 때(즉, 읽기 동작을 끝날 때)까지 이 상태를 유지한다. 한 프로세스가 PENDING LOCK 을 획득하고 있다면 다른 프로세스가 새롭게 SHARED LOCK 을 획득할 수 없다.

EXCLUSIVE : 해당 프로세스가 DB 에 쓰는 상태로 시스템 전체에서 하나의 DB 파일에 오직 하나의 프로세스만이 EXCLUSIVE LOCK 을 획득할 수 있다.



-

BEGIN 으로 트랜잭션을 시작해도 DB 파일은 UNLOCKED 상태를 유지한다.

그 안에서 읽기 동작 수행시 SHARED LOCK 을 획득하고, CUD 작업을 하면 RESERVED LOCK 을 잡으며 저널 파일을 생성한다.



-

두 개의 프로세스가 단일 DB 에 경쟁적으로 접근하면 다음과 같은 상태가 된다.


A                                                                    B

BEGIN; — UNLOCKED

                                                                        BEGIN; — UNLOCKED

                                                                        INSERT … — RESERVED LOCK


SELECT … — SHARED 

INSERT … — RESERVED => SHARED, SQL error db is locked


                                                                        COMMIT — PENDING => RESERVED, SQL error db is locked


INSERT — RESERVED => SHARED, SQL error db is locked


ROLLBACK; — UNLOCKED


                                                                        COMMIT — RESERVED LOCK => UNLOCKED



-

BEGIN 에 option 을 추가해서 트랜잭션 시작과 동시에 UNLOCKED 상태가 아닌 다른 락 상태를 획득할 수 있다.


BEGIN DEFERRED : 트랜잭션의 기본 동작 방식으로 DB 에 읽기/쓰기 동작이 수행될 때까지 어떤 락도 잡지 않는다.

BEGIN IMMEDIATE : 트랜잭션 시작 동시에 RESERVED_LOCK 을 바로 획득한다. 다른 프로세스에서는 IMMEDIATE/EXCLUSIVE LOCK 을 획득할 수 없다.

BEGIN EXCLUSIVE : 트랜잭션 시작과 동시에 EXCLUSIVE LOCK 을 획득한다. 다른 프로세스에서는 읽기뿐 아니라 쓰기 동작도 할 수 없다.






12. 다른 DB 파일 연결


-

하나의 DB 파일로 작업하는 도중 물리적으로 다른 DB 에 접근해서 입력하거나 조회해야 하는 경우가 있다.

이런 경우에는 ATTACH DATABASE 구문을 사용해서 현재의 DB 연결(Connection)에 추가적으로 다른 DB 를 연결해 CRUD 를 할 수 있다.



ATTACH DATABASE


-

syntax

ATTACH DATABASE [dbFileName] AS [dbAlias];


최대로 추가 연결할 수 있는 DB 파일 개수는 SQLite3 lib 을 컴파일할 때 지정하는 SQLITE_MAX_ATTACHED 값을 따른다.



-

ATTACH 로 연결된 DB 에 접근하려면 ATTACH 구문에서 정의한 ‘DB Alias’ 를 사용해야 하며, 기본적으로 연결된 DB 에는 자동적으로 main 이라는 별칭이 부여된다.


DB 간에 동일한 테이블 이름이 존재하지 않는 경우에는 DB 별칭을 생략할 수 있다.



-

ATTACH 된 DB 가 쓰기권한이 있다면 레코드 입력/삭제, 테이블 인덱스 생성 등의 연산도 가능하다.



DETACH DATABASE


syntax

DETACH DATABASE [dbAlias]



-

기본적으로 ATTACH 명령어로 연결된 DB 간의 트랜잭션은 단일 파일의 트랜잭션처럼 여러 DB 파일이 묶여서 원자적으로 동작한다.

하지만 main DB가 메모리 DB(sqlite3_open() 함수를 호출할 때 인자로 “memory:” 를 설정한) 일 때는 개별 DB 파일 단위로 트랜잭션이 유지된다.

이 경우 커밋 도중 비정상적으로 트랜잭션이 종료되면 일부 DB 파일은 수정되고 일부는 수정되지 않는 문제가 발생할 수 있다.




13. 동적 자료형


-

대부분의 DBMS 는 static data type 을 사용한다.

SQLite3 은 다른 DBMS 와 달리 dynamic data type 을 사용한다.

즉, 자료형은 그것을 저장하는 저장소가 아닌 값 자체로 결정되며, 그 결과 테이블을 생성할 때 선언한 컬럼의 자료형과 다른 경우에도 데이터를 저장할 수 있다.

그래서 테이블을 생성할 때 컬럼의 자료형을 명시하지 않더라도 동작하는 데 아무런 문제가 없다.



-

SQLite3 에서는 동작 자료형을 지원하기 위해 스토리지 클래스(storage class)타입 선호도(type affinity)라는 개념을 이용한다.



스토리지 클래스


-

storage class 는 각 값에 할당되는 일종의 태그 정보로서 SQLite3에 저장되는 모든 값은 아래의 스토리지 클래스 중 하나에 속한다.


NULL, INTEGER, REAL(8bit), TEXT, BLOB



-

INTEGER 의 경우 최소한의 디스크 공간을 사용하기 위해 값의 크기에 따라 가변 길이인 1, 2, 3, 4, 6, 8 바이트에 저장되지만 디스크에서 로딩되어 메모리 공간으로 올라갈 때 내부적으로 고정 길이 8바이트로 변환된다.



-

TEXT 의 경우 기본 인코딩은 UTF-8 이며, UTF-16BE, UTF-16LE 로 변경이 가능하며, BLOB 은 주소록에서 이미지를 직접 DB 에 저장하는 경우처럼 외부에서 전달된 바이너리 데이터를 그대로 저장할 때 사용한다.



-

참/거짓을 표현하는 불린(boolean) 타입은 SQLite3 에서는 별도로 존재하지 않고, INTEGER 값을 지정해서 사용한다.

false 는 0, true 는 1 을 사용한다.



-

짜나 시간 데이터를 저장하기 위한 별도의 스토리지 클래스 대신 TEXT(YYYY-MM-DD HH:MM:SS.SSS), REAL(줄리안 날짜), INTEGER(유닉스 시간)형태로 사용한다.



타입 선호도


동적 자료형을 사용하는 SQLite3 에서는 테이블을 생성할 때 컬럼 이름 뒤에 작성하는 것이 컬럼 타입(column type)이 아니라 컬럼의 선호도(type affinity)이다.

타입 선호도가 있는 경우에는 컬럼에 저장할 수 있는 데이터 타입이 특별히 정해지는 것이 아니라 단순히 “우선순위”만을 가진다.

이 말은 타입의 선호도에 따라 데이터의 값이 형변환되어 저장이 된다는 것이다.


int_aff        typeof(int_aff)        txt_aff            typeof(txt_aff)

==============================================

10              integer                  String             text

123            integer                  10.52              text

123String   text                       20                  text


타입 선호도는 해당 컬럼에 저장될 데이터 타입을 추천할 뿐이지 정적 타입처럼 해당 타입의 데이터만 저장하도록 강제하는 것은 아니다.



-

SQLite3 에서 지원하는 5가지 타입 선호도는 아래와 같다.


TEXT : NULL, TEXT, BLOB 형태의 스토리지 클래스를 이용해서 저장된다. 숫자형태(INTEGER, REAL)의 데이터가 이 컬럼에 입력되면 문자열로 형변환되어 저장

NUMERIC : 문자 데이터가 NUMERIC 선호도를 갖는 컬럼에 입력되는 경우 손실이 없고(lossless) 가역적인(reversible) 경우라면 INTEGER 나 REAL 형태로 형변환해서 저장된다. 만약 형변환 시 손실이 발생하면 변환하지 않고 문자열로 저장하게 되며, NULL 이나 BLOB 스토리지 클래스는 특별히 형변환하지 않고 저장

INTEGER : CAST 연산을 제외하면 NUMERIC 선호도와 동일

REAL : 강제로 정수 타입을 부동 수소점 형태로 저장하는 것을 제외하면 NUMERIC 선호도와 동일

NONE : 특별한 타입 선호도 없이 입력되는 값의 스토리지 클래스가 자료형 변환 없이 그대로 입력된다. 테이블을 생성할 때 BLOB 이거나 인식할 수 없는 데이터 타입일 경우 NONE 선호도가 지정



-

일반적인 DBMS 에서는 정적 자료형을 사용하고 자료형의 종류도 많다.

SQLite3 가 이해하기 힘든 동적 자료형을 사용하는 이유 중 하나는 다른 DBMS 에서 사용되던 SQL 구문이 SQLite3 에서 정상적으로 수행되도록 호환성을 갖추기 위해서이다.


INT 가 있는경우 INTEGER 선호도로 판별

CHAR, CLOB, TEXT 가 있는 경우 TEXT 선호도로 판별

BLOB 이나 타입 선언이 없는 경우 NONE 선호도로 판별

REAL, FLOAT, DOUBLE 인 경우 REAL 선호도로 판별

그 밖의 다른 경우는 NUMERIC 선호도로 판별


위의 판별은 순서 우선순위를 갖는다.

예를 들어 CHARINT 의 경우 TEXT 가 아닌 INTEGER 우선순위를 갖는다.



-

한 테이블의 동일한 컬럼이더라도 서로 다른 스토리지 클래스가 저장될 수 있다. 


비교 규칙은 다음과 같이 작동한다.


NULL 은 어떠한 스토리지 클래스보다 작다.

INTEGER 나 REAL 클래스는 TEXT 나 BLOB 클래스보다 작디.

이 때 INTEGER 나 REAL 클래스 간의 크기 비교는 숫자 크기 비교에 해당한다.

TEXT 클래스는 항상 BLOB 보다 작다

이 때 두 TEXT 클래스 간의 크기를 비교할 때는 COLLATION 함수를 이용한다.

BLOB 값 간의 크기 비교는 C 언어의 memcmp() 함수와 동일한 방식으로 비교한다.


NULL < INTEGER / REAL < TEXT < BLOB



-

TEXT 선호도가 있는 column 과 숫자를 비교하게 되면 숫자 값이 암시적으로 형변환되어 비교한다.


반대로 NUMERIC, INTEGER, REAL 선호도를 갖는 column 과 문자를 비교하게 되면, 문자열을 형변환 숫자 형태로 가능하다면 암시적 변환 후 비교한다.

형변환 할 수 없는 경우에는 서로 다른 스토리지 클래스 간의 비교 규칙에 의해 TEXT 가 무조건 큰 값으로 판별된다.


BLOB 의 경우 형변환이 발생하지 않으며, 스토리지 클래스 간의 비교 규칙에서 BLOB 은 가장 큰 것으로 판별된다.



-

+, - 와 같은 연산 과정에서도 암시적 형변환이 일어난다.


하나의 피연산자가 INTEGER, REAL, NUMERIC 선호도를 갖고, 다른 하나가 TEXT 나 NONE 을 갖는 경우 후자가 NUMERIC 으로 형변환된다.

피연산자 하나가 TEXT 선호도를 갖고 다른 하나가 NONE 인 경우, NONE 이 TEXT 로 변환된다.

모든 NULL 과의 연산 결과로는 NULL 이 반환된다.

그 외 변환할 수 없는 경우에는 0이나 0.0의 값으로 형변환된다.


ex)

10 + ’20’ -> 30

10 + ‘String’ -> 10

NULL + 10 -> NULL

NULL > 10 -> NULL

NULL AND 1 -> NULL



명시적 형변환


-

CAST 연산자를 이용하면 명시적으로 데이터의 스토리지 클래스 타입을 변경할 수 있다.


syntax

CAST([표현식] AS [스토리지 클래스 타입])


ex) 

SELECT 10.25, CAST(10.25 AS INTEGER), CAST(10.25 AS TEXT);



-

CAST 연산자를 이용해 숫자와 문자가 함께 존재하는 TEXT 데이터를 INTEGER 나 REAL 로 형변환하는 경우 최대한 변환할 수 있는 만큼 값을 변환한다.

‘10ABCD20’ -> 10

‘ABCD10’ -> 0



내장 정렬 함수


DB 에서 두 문자열을 정렬하기 위해 어떤 문자열이 더 큰지 비교할 때 사용되는 함수를 정렬 함수(collating function) 라고 한다.

기본적으로 SQLite3 에서는 아래의 3개 내장 정렬 함수를 제공한다.


BINARY : 문자열을 인코딩과 상관없이 C 언어의 memcmp() 함수와 동일한 방식으로 비교한다.(기본값)

NOCASE : BINARY 와 동일하나 알파벳 26자리에 대해서는 대소문자를 구별하지 않는다.

RTRIM : BINARY 와 동일하나 문자열의 오른쪽 끝에 오는 공백은 비교 시 제외한다.



-

테이블을 생성할 때 정렬 함수를 지정하는 경우 CREATE TABLE 구문에서 컬럼 이름과 자료형 이후에 COLLATE [정렬함수] 형태로 작성하면 된다.

SELECT 구문에서 정렬 함수를 변경하는 경우에도 ORDER BY 다음에 COLLATE [정렬함수] 형태로 작성하면 된다.


ex)

CREATE TABLE collationTest( txt, txt_bin COLLATE BINARY, … );


SELECT * FROM collationTest WHERE txt_bin=‘SqLiTe’ COLLATE NOCASE;




반응형

'프로그래밍 놀이터 > Database' 카테고리의 다른 글

[SQLite3] 05. SQLite3 C API 고급  (0) 2018.05.21
[SQLite3] 04. SQLite3 C API 기초  (4) 2018.05.20
[SQLite3] 03. SQL 고급 #2  (0) 2018.05.19
[SQLite3] 03. SQL 고급 #1  (0) 2018.05.18
[SQLite3] 02. SQLite3 설치  (0) 2018.05.17
[SQLite3] 01. SQLite 소개  (0) 2018.05.16

댓글0