1. SELECT ~ INTO

문법 : SELECT * INTO [신규테이블] FROM [원본테이블]


- 테이블을 새로 생성해서 INSERT 할 때 사용


2. INSERT ~ INTO

문법 : INSERT INTO [신규테이블] (필드1, 2, 3....) SELECT (필드1, 2, 3....) FROM [원본테이블]


- 기존 테이블에 INSERT 할 때 사용

'공부방 > DB' 카테고리의 다른 글

[MS-SQL] DB별 BUFFER MEMORY 사용량 보기  (0) 2015.12.10
[MS-SQL] SA 비밀번호 변경  (0) 2015.03.25
[MS-SQL] LOCK에 관해서  (2) 2014.10.10
[MS-SQL] 데이터 형식 변환  (0) 2014.08.28
[MS-SQL] 테이블 명, 컬럼명 변경하기  (0) 2014.07.04

1. Lock의 유형

Lock Compatibility

다음은 Lock에 종류에 대해서 알아보도록 하겠습니다. 
Lock의 종류에 대해서 알아보기 전에 우선 Data Manipulation Language에 대해서 다시 한 번 돌아보도록 하겠습니다. DML에는 어떠한 구문이 있는지 기억이 나시는지 모르겠습니다. 
물론 Data를 반환하는 SELECT문, 입력연산을 수행하는 INSERT문, 갱신연산을 위한 UPDATE문, 삭제연산을 위한 DELETE문 등으로 나뉠 수 있다고 말씀을 드렸습니다. 
이는 특성상 2가지로 분류를 할 수 있습니다. 우선 Data에 변경작업은 가하지 않고, 다만 Data,에 대한 반환작업만을 하는 SELELCT 구문과 Data에 대한 변경작업을 하는 INSERT, UPDATE, DELETE 등으로 나눌 수 있습니다. Transaction 역시 이러한 DML문장을 이용하므로 Transaction에 대해서 Lock을 거는 것 또한 비슷합니다.


종류구문특성
Shared Lock(공유 Lock) - Read LockSELECT

다른 Lock과 공유됨. 
읽기 전용 작업 
Data 변경은 불가

Exclusive Lock(단독 Lock) - Write LockINSERT, 
UPDATE, 
DELETE

다른 Lock과는 공유되지 않음 
쓰기 작업 
동일 Data에 대해서 반드시 하나의 Exclusive Lock만이 걸림


SELECT문을 수행하게 되면 걸리는 Lock은 Shared Lock. 즉 공유 Lock이라고 하는 것이 걸리게 됩니다. 이는 Read Lock(읽기 Lock)라고도 합니다. 즉, SELECT문과 같이 읽기 작업을 하는 Data영역에 대해서 Lock을 거는 것을 말합니다. 기본적으로 공유 Lock은 읽기 작업 동안에만 걸리게 됩니다. 즉, SELECT문에 의해서 Data를 반환 받고 나면 바로 Lock은 해제되게 됩니다.

다음의 Exclusive Lock은 INSERT, UPDATE, DELETE 구문과 같이 Data에 대해서 변경작업을 하거나 쓰기 작업을 하는 동안 걸리게 됩니다. 이는 Transaction 전체에 대해서 Lock을 가지고 있고, Commit이나 Rollback으로 해당 Transaction을 종료하게 되면 Lock은 해제되게 됩니다.

이 두 개의 Lock 사이에는 가지고 있는 특성에 따라서 Lock을 공유할 수도, 공유하지 않을 수도 있습니다. 이러한 특성을 표현을 한 것이 다음의 표입니다.


 X(Exclusive Lock)Shared Lock(S)
X(Exclusive Lock)

×

×

Shared Lock(S)

×


보시는 바와 같이 단독 Lock(Exclusive Lock)이 걸려있는 경우에는 어떠한 Lock도 같이 Lock을 걸 수 없습니다. 공유 Lock(Shared Lock)이 걸려 있는 경우에는 공유 Lock은 같이 Lock을 걸어서 사용을 할 수 있지만, Exclusive Lock을 걸 수는 없습니다. 
조금 헤깔리는데요. 
하나하나 설명을 드리도록 하겠습니다. 
우선 Transaction A에서는 고객정보 Table에 Insert 작업(입력연산)을 수행하고 있습니다. 이러한 경우라면 Exclusive Lock가 걸리게 되는 데요. 이때 Transaction B가 같은 고객정보 Table에 Update 작업(갱신연산)을 수행하려고 합니다. 이러한 경우에 Transaction B는 Update 작업을 할 수 없게 됩니다. 이는 Transaction A가 이미 독점 Lock을 걸어서 다른 Lock을 공유할 수 없게끔 만들었기 때문에, Transaction B는 Transaction A가 작업을 마치게 될 때까지, 기다려야만 합니다.

만약 이 때 Transaction B가 갱신연산을 포기하고, 어떤 Data가 들어 있는지 SELECT문을 이용하여, Data를 반환하려 한다면, 즉 공유 Lock를 걸려고 하면 어떻게 될까요? 
표에서 보시는 바와 같이 공유 Lock을 걸어달라는 요청 또한 Transaction A는 무시하게 됩니다. 즉, 고객정보 Table의 Data는 변경 중이니, Data를 보여줄 수도 없고, 다른 Transaction이 변경도 할 수 없다는 것입니다.

그럼 Transaction A가 SELECT문을 이용하여 공유 Lock을 걸었을 경우에는 어떨까요? 
먼저 Transaction B가 삭제연산을 수행하려고, 독점 Lock을 요청했을 경우에는 요청을 무시하게 됩니다. 즉, Transaction A가 현재 Data를 보고 읽고 있기 때문에, 읽기 작업이 끝날 때까지 기다려야만 합니다. 그래서 Transaction B는 다시 SELECT문을 이용하여 Data반환 작업을 실행하였습니다. 이렇게 같이 읽기 작업을 하기 위해 공유 Lock을 요청하였을 경우에는 공유 Lock을 허용하게 됩니다. 현재 읽고 있는 Data에 대해서 어떠한 변경작업도 가해지지 않기 때문입니다.

이외에도 특수한 형태의 Lock들이 있습니다. 굳이 이 모든 Lock을 다 이해하고 넘어가실 필요는 없습니다. 다만 이런 것들이 추가적으로 더 있다는 것만 알고 넘어가도록 하겠습니다.

- Intent Lock(IX) 
SQL Server에서 내부적으로 Lock의 충돌을 줄이기 위해서 사용됩니다. 내재된 잠금은 SQL Server가 계층 아래쪽에 있는 일부 리소스에 대해 공유(S) 잠금 또는 단독(X) 잠금을 얻으려 할 때 발생합니다. 예를 들어, 내재된 공유 잠금을 테이블 수준에서 설정한다는 것은 트랜잭션이 해당 테이블의 페이지 또는 행에 대해 공유(S) 잠금을 설정하려고 하는 것입니다. 테이블 수준에서 내재된 잠금을 설정하면 이후에 다른 트랜잭션이 해당 페이지를 포함하는 테이블에 대해 단독(X) 잠금을 얻을 수 없습니다. SQL Server는 테이블 수준에서만 내재된 잠금을 확인하여 트랜잭션이 해당 테이블에 대해 잠금을 얻을 수 있는지 확인하므로 내재된 잠금을 사용하면 성능이 향상됩니다. 이 경우 테이블의 모든 행 또는 페이지 잠금을 확인하여 트랜잭션이 전체 테이블을 잠글 수 있는지 확인할 필요가 없습니다.

- Update Lock(U) 
업데이트(U) 잠금을 사용하면 일반적인 형태의 교착 상태가 방지됩니다. 일반적인 업데이트 패턴은 레코드를 읽고, 리소스(페이지 또는 행)에 대한 공유(S) 잠금을 얻은 다음 행을 수정하는 트랜잭션으로 구성되는데 행을 수정할 때는 단독(X) 잠금으로 잠금을 변환해야 합니다. 두 트랜잭션에서 리소스에 대해 공유 모드 잠금을 얻은 다음 데이터를 동시에 업데이트하려고 하면 한 트랜잭션이 단독(X) 잠금으로 잠금을 변환하려 합니다. 한 트랜잭션의 단독 잠금은 다른 트랜잭션의 공유 모드 잠금과 호환되지 않으므로 공유 모드를 단독 모드로 변환할 때는 잠금 대기가 발생합니다. 두 번째 트랜잭션이 해당 업데이트에 대해 단독(X) 잠금을 얻으려고 합니다. 이 경우 두 트랜잭션 모두 단독(X) 잠금으로 변환 중이고 각각 상대 트랜잭션이 공유 모드 잠금을 해제하기를 기다리므로 교착 상태가 발생합니다.

이러한 교착 상태를 방지하려면 업데이트(U) 잠금을 사용합니다. 한 번에 한 트랜잭션만 리소스에 대한 업데이트(U) 잠금을 얻을 수 있습니다. 트랜잭션이 리소스를 수정하면 업데이트(U) 잠금이 단독(X) 잠금으로 변환되고 그렇지 않으면 잠금이 공유 모드 잠금으로 변환됩니다.

- Schema Lock 
스키마 수정(Sch-M) 잠금은 열을 추가하거나 테이블을 삭제하는 등 테이블 데이터 정의 언어(DDL) 작업이 수행 중일 때 사용됩니다.

스키마 안정성(Sch-S) 잠금은 쿼리를 컴파일할 때 사용됩니다. 스키마 안정성(Sch-S) 잠금은 단독(X) 잠금 등 다른 트랜잭션 잠금을 차단하지 않습니다. 따라서 쿼리가 컴파일되는 동안 테이블에 대한 단독(X) 잠금을 포함하여 다른 트랜잭션을 계속 실행할 수 있습니다. 그러나 테이블에서 DDL 작업은 수행할 수 없습니다.

- Bulk Update Lock 
대량 업데이트(BU) 잠금은 테이블로 데이터를 대량 복사하고 TABLOCK 참고가 지정되거나 sp_tableoption을 사용하여 table lock on bulk load 테이블 옵션이 설정될 때 사용됩니다. 대량 업데이트(BU) 잠금을 사용하면 여러 프로세스가 데이터를 동시에 같은 테이블로 대량 복사할 수는 있지만, 데이터를 대량 복사하지 않는 다른 프로세스가 테이블에 액세스하는 것을 방지할 수 있습니다.


 ISSUIXSIXX
Intent shared(IS)X
Shared(S)XXX
Updated(U)XXXX
Intent Exclusive(IX)XXXX
Shared with intent 
exclusive(SIX)
XXXXX
Exclusive(X)XXXXXX


2. Managing Locks

이제 SQL Server에서 Lock을 사용하는 방법에 대해서 알아보도록 하겠습니다. 먼저 앞서 설명을 드렸던 Lock이 없는 경우에 발생할 수 있는 문제점에 대해서 Lock을 사용하면, 어떻게 해결할 수 있는지. 그 종류와 어떻게 사용하면 해결되는지에 대해서 알아보고, Lock을 사용하면서 발생될 수 있는 문제점에 대해서도 알아보도록 하겠습니다. 
마지막으로 Lock에 대한 현황을 볼 수 있는 여러 Option들에 대해서도 살펴보기로 하겠습니다. 먼저 Lock을 사용하는 방법에 대해서 알아보도록 하겠습니다.

- Session-Level Locking Options

SQL Server에서 Lock은 4가지의 Option으로 제공이 됩니다. 이 4가지 Option은 그 Lock의 간섭의 정도(degree of interference)에 따라서 사용되어지게 됩니다.

이를 level of isolation 또는 isolation level이라고 합니다. 저희는 고립화 수준이라는 용어를 사용하도록 하겠습니다. 고립화 수준은 SQL Server에서 정의한 것이 아니라, ANSI-SQL에서 정의한 것을 기준으로 SQL Server에서 각 Level에 해당하는 Lock를 지원하는 것입니다.

고립화 수준(isolation level)은 주어진 Transaction이 병행수행되는 Transaction의 부분으로 허용될 수 있는 간섭의 정도를 말합니다.

이러한 간섭의 정도가 어느 정도로 강력한지에 따라서 4가지 Level로 나누게 됩니다.

이러한 Isolation Level은 Session별로 정의가 가능합니다. Session은 사용자가 SQL Server로 연결되어 있는 일정 시간을 말하는 것입니다. Session에 대해서는 실습을 통해서 직접 보여드리도록 하겠습니다.

이제 Isolation Level에 대해서 하나하나 알아보도록 하겠습니다.


ANSI - SQL Isolation LevelSQL Isolation Level발생되는 문제점
Level 0READ UNCOMMITTEDDirty Read, 
Nonrepeatable Read, 
Phantom Read
Level 1READ COMMITTEDNonrepeatable Read, Phantom Read
Level 2REPEATABLEPhantom Read
Level 3SERIALIZABLE 


먼저 READ COMMITTED입니다. READ COMMITTED는 MSSQL Server의 기본적인 Isolation Level입니다. 따라서 지금까지 Transaction을 정의하면서 아무런 Option도 지정하지 않았는데, 이는 아무런 Level도 지정을 하지 않으면 기본값으로 READ COMMITTED가 설정되어 사용되기 때문에 저희도 모르는 사이에 Isolation Level을 설정하여 사용하고 있었던 것입니다.

이는 변경된 Data에 대해서는 Exclusive Lock을 지정하게 됩니다. 따라서 해당 Transaction에 대해서 Commit이나 Rollback을 이용하여 Transaction을 종료하지 않은 경우에는 해당 Data를 읽어 올 수도, 변경할 수도 없습니다. 
그렇다면 앞서 설명 드렸던 문제점 중에서 두개의 문제는 해결하였습니다. 
READ COMMITTED으로 정의된 Transaction에서는 Lost Update와 Dirty Read는 발생되지 않게 될 것입니다. 그 이유는 실습을 통해서 설명을 드리도록 하겠습니다.

다음은 READ UNCOMMITTED입니다. READ UNCOMMITTED는 Dirty Read를 가능하게 합니다. 즉, Transaction 내의 해당 Data가 변경되었더라도, 다른 Transaction에서 해당 Data를 읽어 갈 수 있도록 Shared Lock을 허용하게 됩니다. 하지만 이미 변경한 Data에 대해서, 다른 Transaction에서 변경을 할 수 없도록 Exclusive Lock을 지원합니다. 즉 Lost Update에 대한 문제는 해결하지만, Dirty Read에 대한 문제는 발생하게 됩니다. 따라서 잘못된 Data를 반환할 수 있는 문제점을 가지고 있습니다. 
다음은 REPEATABLE READ입니다. REPEATABLE READ는 SELECT한 Data에 대해서 설정된 Shared Lock이 Transaction이 종료되는 시점까지 연장되는 것을 말합니다. 즉 Transaction 안에서 SELECT문을 이용하여 반환된 Data에 대해서 다른 Transaction에서 반환을 요구하는 SELECT문장을 실행하였을 경우에는 앞서 실행되었던 Transaction이 종료될 때까지 기다려야만 합니다. 물론 해당 Data에 대한 변경은 불가능합니다. 
즉, 이는 반복적으로 Data를 읽어도 같은 Data를 읽어 올 수 있도록 지원하는 Isolation Level입니다. 따라서 이는 Nonrepeatable Read라는 문제점을 해결하여 줍니다. 하지만, 이는 SELECT로 읽어온 Data에 대해서만 적용이 되기 때문에, 입력되는 Data에 대해서는 간섭을 할 수 없습니다. 따라서 Phantom Read라는 문제점은 아직도 발생되게 됩니다.

마지막으로 SERIALIZABLE은 가장 강력한 Isolation Level입니다. SERIALIZABLE은 SELECT절에 의해서 반환된 Data에 대해서 SELECT나 변경은 물론 INSERT도 불가능하게 하는 Isolation Level입니다. 따라서 이는 Phantom Read의 문제점 까지도 보완을 할 수 있습니다.

이를 정리하면 다음의 표와 같이 정리를 할 수 있습니다.


Isolation Level발생되는 문제해결되는 문제SELECTINSERTUPDATEDELETE
READ COMMITTEDNonrepetable Read 
Phantom Read
Lost Update 
Dirty Read
XXX
READ UNCOMMITTEDDirty Read 
Nonrepeaable Read 
Phantom Read
Lost UpdateXX
REPEATABLE READPhantom ReadLost Update 
Dirty Read 
Nonrepeatable Read
XXX
SERIALIZABLE-Lost Update 
Dirty Read 
Nonrepeatable Read
Phantom Read
XXXX


어떻게 활용이 되는지에 대해서는 실습을 통해서 설명을 드리도록 하겠습니다. 
Transaction에 Isolation Level을 정의하는 기본적인 구문은 다음과 같습니다.


SET TRANSACTION ISOLATION LEVEL 
     {READ COMMITTED| 
     READ UNCOMMITTED| 
     REPEATABLE READ| 
     SERIALIZABLE}


보시는 것과 같이 Transaction을 시작하는 문장 앞에 Transaction의 Isolation Level을 지정하는 문장을 사용하여 해당하는 Transaction의 Isolation Level을 설정할 수 있습니다.

이렇게 Transaction의 Isolation Level을 적절하게 설정하여 사용을 한다면, Data의 일치성이나 효율적인 Data의 관리를 할 수 있을 것입니다. 하지만, Isolation Level이 강력할수록 좋은 것은 아닙니다. 예를 들어, 테이프 Table에 대해서 Serializable로 설정을 하고 모든 Data에 대해서 검색을 하였다면, 다른 사용자가 테이프에 대한 내역은 절대 볼 수 없게 됩니다. 이러한 경우 Transaction을 짧게 사용하였다면, 다른 사용자가 자신이 다른 Transaction의 Lock에 의해서 기다리고 있다는 사실 조차도 모르겠지만, 만약 사용자가 Transaction을 시작하고 종료도 하지 않은 채, 점심식사를 하러 갔다든지, 아니면 퇴근을 하였을 경우에는 다른 사용자는 테이프에 대한 Data는 아무 것도 반환을 할 수 없습니다. Transaction이 끝나는 시간까지 기다려야만 합니다. 따라서 이러한 경우, Lock에 의해서 Data를 반환하지 못하거나 갱신을 할 수 없다면, 해당 Transaction이 끝나기를 기다릴 수 있는 시간을 설정하여주면 됩니다.

이를 Locking Timeout이라고 합니다. 다음은 LOCKING TIMEOUT의 기본적인 구문입니다.


SET LOCK_TIMEOUT timeout_period


Timeout_period의 값은 milliseconds 단위입니다. 실습을 통해서 사용 예를 보여드리도록 하겠습니다. 
이러한 Timeout 속성에 대해서는 @@lock_timeout이라는 전역변수를 이용해서 정보를 얻을 수 있습니다.


원본링크 : http://www.mssql.org/LectureSQL/01_sql7/lock_02.asp

'공부방 > DB' 카테고리의 다른 글

[MS-SQL] SA 비밀번호 변경  (0) 2015.03.25
[MS-SQL] SELECT ~ INTO, INSERT ~ INTO  (0) 2015.03.16
[MS-SQL] 데이터 형식 변환  (0) 2014.08.28
[MS-SQL] 테이블 명, 컬럼명 변경하기  (0) 2014.07.04
[DB] 서버정보 보기  (0) 2013.12.13
1. 데이터 형 변환

데이터 형식 변환엔 암시적 형 변환과 명시적 형 변환, 두 가지 방법론이 있다.

명시적 형 변환이란 CAST() / CONVERT()의 데이터 형 변환 함수를 사용하는 것을 의미하며,
암시적 형 변환이란 데이터 형식간의 연산을 통해 데이터 형식이 변환되는 것을 의미한다.

우선 명시적 형 변환부터 알아보도록 하자.


2. 명시적 형 변환


명시적 형 변환은 CAST()와 CONVERT() 함수를 통해 수행할 수 있다.
두 함수는 형식만 다를 뿐 거의 비슷한 기능을 한다.

  1. CAST (expression AS 데이터형식 [(길이)])
  2. CONVERT (데이터형식 [(길이)], expression [, 스타일])

데이터 형식에 따라 길이 지정이 필요한 형식이 있을 수 있다. 
(nchar, nvarchar, char, varchar, binary 또는 varbinary)

이제 기본적인 사용 예제를 살펴보도록 하자.

  1. -- Amount가 정수이기에, AVG값을 소수로 표현하기 위해 1.0을 곱하였다.
  2. -- 이게 암시적 형 변환
  3. SELECT ID, AVG(Amount * 1.0) AS AmountAvg FROM BuyTable
  4. GROUP BY ID

위 예제에서는 Amount의 AVG값을 소수형으로 표현하기 위해 1.0을 곱하는 암시적 형 변환을 사용하였다.
이것을 CAST() / CONVERT()를 통해 명시적 형 변환을 해 보자.

  1. -- CAST 함수를 통한 명시적 형 변환
  2. SELECT ID, AVG(CAST(Amount AS FLOAT)) AS AmountAvg FROM BuyTable
  3. GROUP BY ID
  4.  
  5. -- CONVERT 함수를 통한 명시적 형 변환
  6. SELECT ID, AVG(CONVERT(FLOAT, Amount)) AS AmountAvg FROM BuyTable
  7. GROUP BY ID

아래 예제는 정수와 정수를 나누었을 때, 이를 실수로 표현하고 정확히 출력하고픈 소수점 자릿수를 지정하는 예제이다.

  1. -- Price, Amount 모두 정수형이기에, Price/Amount 역시 정수형.
  2. -- 따라서 정확히 표현되지 않고, 소수점 이하가 모두 잘린다.
  3. SELECT Price, Amount, Price/Amount AS [단가/수량] FROM BuyTable
  4.  
  5. -- 이를 우선 실수형으로 표현해 보자
  6.  
  7. -- CAST 함수를 사용
  8. SELECT Price, Amount, CAST(Price AS FLOAT) / Amount AS [단가/수량] FROM BuyTable
  9.  
  10. -- CONVERT 함수를 사용
  11. SELECT Price, Amount, CONVERT(FLOAT, Price) / Amount AS [단가/수량] FROM BuyTable

테스트를 해 보면, 원하는 대로 실수형으로 결과가 제대로 표현된다.
그런데 소수점이 너무 길게 나와, 그냥 소수점은 2 자리까지만 표현하고 싶어졌다.

그렇다면 아래와 같이 전체 결과값의 데이터 형식을 명시적으로 지정해 주면 된다.

  1. -- CAST 함수를 한번 더 사용하여, 전체 결과값을 DECIMAL 형식으로 변환한다
  2. SELECT Price, Amount, CAST(CAST(Price AS FLOAT) / Amount AS DECIMAL(102)) AS [단가/수량]
  3. FROM BuyTable
  4.  
  5. -- CONVERT 함수를 한번 더 사용하여, 전체 결과값을 DECIMAL 형식으로 변환한다
  6. SELECT Price, Amount, CONVERT(DECIMAL(102)CONVERT(FLOAT, Price) / Amount) AS [단가/수량]
  7. FROM BuyTable

또한, CONVERT 함수는 변환 스타일도 지원한다.
  • 날짜와 시간의 형식을 갖춘 문자열을 DATETIME 또는 SMALLDATETIME으로
  • DATETIME 또는 SMALLDATETIME을 문자열 데이터 형식으로
  • 또는 FLOAT, REAL, MOMEY, SMALLMONEY 등을 문자열 형식으로 
위 경우들에 대해 각각 정확히 어떠한 데이터 형식으로 변환되어야 하는지를 스타일을 통해 지정할 수 있다.
(이에 대한 자세한 내용은 위에 언급한 MSDN 페이지를 참고하자)

아래 예제를 통해 CONVERT에서 지원하는 스타일에 대해 살펴보자.

  1. SELECT
  2.    -- GETDATE()는 현재 날짜/시간을 DATETIME 형식으로 얻어온다.
  3.    GETDATE() AS UnconvertedDateTime,
  4.    -- GETDATE()의 결과를
  5.    CAST(GETDATE() AS NVARCHAR(30)) AS UsingCast,
  6.    -- 126 스타일은 ISO8601 형식이며 포맷은 다음과 같다
  7.    -- yyyy-mm-ddThh:mi:ss.mmm(공백 없이)
  8.    CONVERT(NVARCHAR(30)GETDATE()126) AS UsingConvertTo_ISO8601

위 예제의 결과는 아래와 같다.


3. 암시적 형 변환

암시적 형 변환은 CAST() / CONVERT() 등의 명시적 형 변환 함수를 호출하지 않고,
데이터 형식 간의 비교나 연산에 의해 데이터 형식이 변경되는 것을 뜻한다.

아래 예제들을 통해 어떻게 형 변환이 일어나는지 살펴 보도록 하자.

  1. DECLARE @CharVar CHAR(3)
  2. SET @CharVar = '100'
  3.  
  4. -- 문자 + 문자 = 문자
  5. SELECT @CharVar + '200'
  6.  
  7. -- 문자 + 정수 = 정수 (문자열이 정수로 변환된 뒤 계산된다)
  8. SELECT @CharVar + 200
  9.  
  10. -- 문자 + 실수 = 실수 (문자열이 실수로 변환된 뒤 계산된다)
  11. SELECT @CharVar + 200.0

위 예제의 결과는 다음과 같다.


위 암시적 형 변환을 명시적으로 수정하면 아래와 같다.

  1. DECLARE @CharVar CHAR(3)
  2. SET @CharVar = '100'
  3.  
  4. -- 같은 타입이므로 굳이 형 변환이 필요 없다.
  5. SELECT @CharVar + '200'
  6.  
  7. -- CAST를 통한 방법
  8. SELECT CAST(@CharVar AS INT) + 200
  9. SELECT CAST(@CharVar AS DECIMAL(5,1)) + 200.0
  10.  
  11. -- CONVERT를 통한 방법
  12. SELECT CONVERT(INT, @CharVar) + 200
  13. SELECT CONVERT(DECIMAL(5,1), @CharVar) + 200.0


4. 데이터 형식 변환 테이블

아래 테이블은 데이터 형식간 변환이 가능한 관계를 나타내고 있다.


5. 명시적 형 변환 vs 암시적 형 변환

명시적 형 변환과 암시적 형 변환 중 무엇을 사용해야 할까?

얼핏 보기에 암시적 형 변환이 코딩량도 줄여주고 훨씬 더 간편해 보이지만,
암시적 형 변환을 믿고 그냥 사용하게 될 경우 원치 않는 결과를 얻을 수도 있다.

다소 불편하더라도 정말~ 명확한 것이 아니라면, 가급적 명시적 형 변환을 하는 습관을 가지도록 하자.


6. 데이터 형식 변환시 주의점

데이터 형 변환시 대표적으로 주의해야 할 것이 있다면,
바로 숫자형 데이터에서 문자형 데이터로 변환할 때 문자의 자릿수를 잘 고려해야 한다는 점이다.

  1. DECLARE @DecimalVar DECIMAL(10,5)
  2. SET @DecimalVar = 10.12345
  3.  
  4. -- 10.12345를 문자로 표현하려면 8글자가 필요한데
  5. -- 변환 대상은 CHAR(5)로 버퍼가 부족하게 된다
  6. SELECT CAST(@DecimalVar AS CHAR(5))

위와 같이 버퍼가 부족하게 되면, 아래와 같은 오류가 발생한다.

메시지 8115, 수준 16, 상태 5, 줄 3
numeric을(를) 데이터 형식 varchar(으)로 변환하는 중 산술 오버플로 오류가 발생했습니다.

그래도 꼬박꼬박 에러를 뿜어주니, 이런 것도 없이 오버플로우가 발생하는 C++보다는 낫다.

무튼, 위 오류를 바로 잡으려면 변환 대상인 CHAR는 적어도 8 바이트 이상으로 지정되어야 한다.

  1. DECLARE @DecimalVar DECIMAL(10,5)
  2. SET @DecimalVar = 10.12345
  3. SELECT CAST(@DecimalVar AS CHAR(8))

그리고 흔히 일어날 수 있는 실수 중 하나는 실수 -> 정수 또는 실수 -> 실수로 변환되면서
소수점 이하의 자리값이 잘릴 수 있다는 점이다.

  1. DECLARE @DecimalVar DECIMAL(10,5)
  2. SET @DecimalVar = 10.12345
  3.  
  4. -- 정수로 변환되면서 소수점 이하 값이 모두 잘림
  5. SELECT CONVERT(INT, @DecimalVar)
  6.  
  7. -- 같은 실수형으로 변환되었지만, 소수점 2 자리값 까지만 보존됨
  8. SELECT CONVERT(DECIMAL(5,2), @DecimalVar)


원본 링크 : http://sweeper.egloos.com/3001863

'공부방 > DB' 카테고리의 다른 글

[MS-SQL] SELECT ~ INTO, INSERT ~ INTO  (0) 2015.03.16
[MS-SQL] LOCK에 관해서  (2) 2014.10.10
[MS-SQL] 테이블 명, 컬럼명 변경하기  (0) 2014.07.04
[DB] 서버정보 보기  (0) 2013.12.13
[MS-SQL] 숫자+문자로 정렬하기  (0) 2013.11.25

+ Recent posts