첨부파일처럼...
IT/SQL SERVER
- SQL Server 2008 평가판에서 정식 버젼으로 업그레이드 방법 2011.08.23
- 간단한 실험. - 숫자타입에 공백 넣기. 2011.08.23
- 알면서도 가끔 헷갈리는 LEFT JOIN 2011.08.09
- [TIP] CTE를 사용해서 복잡한 서브 쿼리 JOIN 구문 정리하기. 2011.08.09
- Oracle START WITH ~ CONNECT BY 절 MSSQL로 처리하기. 2011.08.03
SQL Server 2008 평가판에서 정식 버젼으로 업그레이드 방법
첨부파일처럼...
간단한 실험. - 숫자타입에 공백 넣기.
여러 가지 숫자 형태에 공백을 넣으면 어떤 일이 벌어질까요?
한 번 알아보도록 하죠~
1. 먼저 테이블을 생성합니다.
CREATE TABLE TB_NumberTest
(
SEQ INT IDENTITY(1,1) NOT NULL,
DATATYPE VARCHAR(200) NOT NULL,
ColBigInt BIGINT,
ColBit BIT,
ColDecimal DECIMAL(5,2),
ColInt INT,
ColMoney MONEY,
ColNumeric NUMERIC(5,2),
ColSmallInt SMALLINT,
ColSmallMoney SMALLMONEY,
ColTinyInt TINYINT,
ColFloat FLOAT,
ColReal REAL
)
GO
2. 하나씩 INSERT 합니다. 간혹 오류가 나는 것도 있네요.
INSERT INTO TB_NumberTest (DATATYPE, ColBigInt) VALUES ('ColBigInt', '');
(1 row(s) affected)
INSERT INTO TB_NumberTest (DATATYPE, ColBit) VALUES ('ColBit', '');
(1 row(s) affected)
INSERT INTO TB_NumberTest (DATATYPE, ColDecimal) VALUES ('ColDecimal', '');
Msg 8114, Level 16, State 5, Line 1
Error converting data type varchar to numeric.
INSERT INTO TB_NumberTest (DATATYPE, ColInt) VALUES ('ColInt', '');
(1 row(s) affected)
INSERT INTO TB_NumberTest (DATATYPE, ColMoney) VALUES ('ColMoney', '');
(1 row(s) affected)
INSERT INTO TB_NumberTest (DATATYPE, ColNumeric) VALUES ('ColNumeric', '');
Msg 8114, Level 16, State 5, Line 1
Error converting data type varchar to numeric.
INSERT INTO TB_NumberTest (DATATYPE, ColSmallInt) VALUES ('ColSmallInt', '');
(1 row(s) affected)
INSERT INTO TB_NumberTest (DATATYPE, ColSmallMoney) VALUES ('ColSmallMoney', '');
(1 row(s) affected)
INSERT INTO TB_NumberTest (DATATYPE, ColTinyInt) VALUES ('ColTinyInt', '');
(1 row(s) affected)
INSERT INTO TB_NumberTest (DATATYPE, ColFloat) VALUES ('ColFloat', '');
(1 row(s) affected)
INSERT INTO TB_NumberTest (DATATYPE, ColReal) VALUES ('ColReal', '');
(1 row(s) affected)
3. 이제 결과를 보겠습니다.
SELECT * FROM TB_NumberTest;
l 보시는 바와 같이 Numeric Type과 Decimal Type을 제외하고는 에러가 나지 않고 다 0으로 들어갑니다.
작업할 때 혼돈이 없도록 해야겠죠?
참고로… MSSQL에서 DECIMAL과 NUMERIC은 같은 타입입니다.
또, 참고로 Oracle에서는 숫자타입에 '' 을 넣으면 NULL로 처리됩니다.
알면서도 가끔 헷갈리는 LEFT JOIN
LEFT OUTER JOIN 에 대해 그냥 실험하듯이 몇 가지를 해 보았습니다.
그냥 재미로 보시면 될 듯 하네요.
먼저 테이블을 두 개 만들어 보겠습니다.
CREATE TABLE dbo.TB_A
(SEQ1 INT,
DATA1 VARCHAR(1000)
);
CREATE TABLE dbo.TB_B
(SEQ2 INT,
DATA2 VARCHAR(1000)
);
SEQ1, DATA1 과 SEQ2, DATA2 로 되어 있는 간단한 테이블입니다.
여기에 데이터를 삽입합니다.
INSERT INTO TB_A VALUES (1,'테이블A1'), (2,'테이블A2'), (3,'테이블A3'), (4,'테이블A4'), (5,'테이블A5');
INSERT INTO TB_B VALUES (1,'테이블B1'), (3,'테이블B3'), (5,'테이블B5');
1번 테이블엔 다섯 개의 Row가, 2번 테이블엔 세 개의 Row가 있습니다.
1. INNER JOIN해 보면 다음과 같습니다.
SELECT A.*, B.*
FROM TB_A A INNER JOIN TB_B B ON A.SEQ1 = B.SEQ2
당연히 세 개의 결과만 나오죠.
2. 그럼 LEFT OUTER JOIN에서 위와 같은 조건으로 해봅니다.
SELECT A.*, B.*
FROM TB_A A LEFT OUTER JOIN TB_B B ON A.SEQ1 = B.SEQ2
네, 첫번째 테이블의 모든 것과 두번째 테이블에서 SEQ2이 매치되는 것만 보여주죠. 당연한 이야기입니다.
3. 그럼 이제 조건을 좀 바꿔보겠습니다.
SELECT A.*, B.*
FROM TB_A A LEFT OUTER JOIN TB_B B ON A.SEQ1 = B.SEQ2
WHERE A.DATA1 LIKE'%4'
테이블 1에 4가 들어간 Row는 하나 뿐이므로WHERE 조건에 일치하는 것을 먼저 가져오고 나니 두 번째 테이블엔 매치되는 게 없습니다.
4. 그렇다면 저것을 JOIN 조건으로 올리게 되면 어떻게 될까요?
SELECT A.*, B.*
FROM TB_A A LEFT OUTER JOIN TB_B B ON A.SEQ1 = B.SEQ2 AND A.DATA1 LIKE '%4'
아까랑 많이 다릅니다. 이는 일단 기본적으로 테이블1에 있는 모든 것을 가져온 뒤 조건에 맞는 것을 찾기 때문입니다.
5. 그럼, 조건에 맞는 것이 있을 때는 어떻게 될까요?
SELECT A.*, B.*
FROM TB_A A LEFT OUTER JOIN TB_B B ON A.SEQ1 = B.SEQ2 AND B.DATA2 LIKE '%3'
이제 좀 달라졌죠? JOIN조건에 맞는 것이 없을 때와 있을 때는 위와 같이 차이가 납니다.
6. 4.번과 다른 조건으로 한 번 더 봅니다.
SELECT A.*, B.*
FROM TB_A A LEFT OUTER JOIN TB_B B ON A.SEQ1 = B.SEQ2 AND B.DATA2 LIKE '%4'
어라? 결과가 4번과 같습니다… 이는 결국 테이블2에서 매치되는 조건이 없기 때문입니다.
7. 가장 주의해야 할 사항은 지금 보여드리는 쿼리입니다.
SELECT A.*, B.*
FROM TB_A A LEFT OUTER JOIN TB_B B ON A.SEQ1 = B.SEQ2
WHERE B.DATA2 LIKE'%3'
LEFT OUTER JOIN임에도 불구하고 두 번째 테이블의 컬럼 조건을 WHERE절에 쓰면…
해당 조건에 맞는 데이터를 먼저 걸러내게 됩니다.
아마… 실제로 원했던 것은 5.번과 같이 먼저 첫번째 테이블의 모든 결과를 가져온 뒤, 두번째 테이블 조건에 일치하는 것을 찾으려고 했을 것입니다.
계속 쳐다보면 더 헷갈릴 수도 있으니… 원리를 찾아보시면 좋을 듯 합니다. ^^.
[TIP] CTE를 사용해서 복잡한 서브 쿼리 JOIN 구문 정리하기.
안녕하세요...
오늘은 CTE를 사용해서 복잡한 JOIN 구문을 좀 알기 쉽고 편리하게 처리해 볼까 합니다.
먼저 원문입니다.
SELECT AA.SalesOrderID, AA.SalesLastYear, AA.Bonus, AA.Comment, BB.AddressID, BB.CustomerID, BB.AccountNumber, CC.SalesOrderID, CC.SalesPersonID, CC.ShipDate FROM ( SELECT A.SalesOrderID, A.OrderDate, A.Comment, A.SalesPersonID, A.ShipDate, A.CustomerID, B.Bonus, B.CommissionPct, B.SalesLastYear, B.SalesQuota FROM Sales.SalesOrderHeader A, Sales.SalesPerson B WHERE A.SalesPersonID = B.SalesPersonID AND A.SalesOrderID >= 70000 ) AA LEFT OUTER JOIN (SELECT A.CustomerID, A.AccountNumber, A.CustomerType, B.AddressID, B.AddressTypeID FROM Sales.Customer A, Sales.CustomerAddress B WHERE A.CustomerID = B.CustomerID AND A.CustomerID >= 1 AND A.CustomerID <= 20 ) BB ON AA.CustomerID = BB.CustomerID LEFT OUTER JOIN ( SELECT A.SalesOrderID, A.OrderDate, A.Comment, A.SalesPersonID, A.ShipDate, A.CustomerID, B.SalesOrderDetailID, B.ProductID, B.OrderQty FROM Sales.SalesOrderHeader A, Sales.SalesOrderDetail B WHERE A.SalesOrderID = B.SalesOrderID AND A.SalesOrderID >= 70000 ) CC ON AA.CustomerID = CC.CustomerID ; |
보시는 바와 같이 굵은 줄 친 부분 글씨를 유심히 보지 않으면 JOIN 구문 찾기가 쉽지 않습니다. 이것이 CTE를 사용하지 않은 Sub Query 원문이고요.
만약 이것이 여러 개라면 더더욱 복잡해 지겠지요?
그러면 CTE를 사용해서 정리해 보겠습니다.
WITH AA AS ( SELECT A.SalesOrderID, A.OrderDate, A.Comment, A.SalesPersonID, A.ShipDate, A.CustomerID, B.Bonus, B.CommissionPct, B.SalesLastYear, B.SalesQuota FROM Sales.SalesOrderHeader A, Sales.SalesPerson B WHERE A.SalesPersonID = B.SalesPersonID AND A.SalesOrderID >= 70000 ), BB AS (SELECT A.CustomerID, A.AccountNumber, A.CustomerType, B.AddressID, B.AddressTypeID FROM Sales.Customer A, Sales.CustomerAddress B WHERE A.CustomerID = B.CustomerID AND A.CustomerID >= 1 AND A.CustomerID <= 20 ), CC AS ( SELECT A.SalesOrderID, A.OrderDate, A.Comment, A.SalesPersonID, A.ShipDate, A.CustomerID, B.SalesOrderDetailID, B.ProductID, B.OrderQty FROM Sales.SalesOrderHeader A, Sales.SalesOrderDetail B WHERE A.SalesOrderID = B.SalesOrderID AND A.SalesOrderID >= 70000 ) SELECT AA.SalesOrderID, AA.SalesLastYear, AA.Bonus, AA.Comment, BB.AddressID, BB.CustomerID, BB.AccountNumber, CC.SalesOrderID, CC.SalesPersonID, CC.ShipDate FROM AA LEFT OUTER JOIN BB ON AA.CustomerID = BB.CustomerID LEFT OUTER JOIN CC ON AA.CustomerID = CC.CustomerID ; |
각각 With로 시작하고,
Alias와 , 를 사용한 것 외에는 별 다를 것이 없지만.
FROM 절 아래로 JOIN 구문을 내림으로써 훨씬 보게 좋게 JOIN 확인이 가능합니다. ^^.
간단한 팁이지만, 부득이하게 Sub Query가 많아질 경우 JOIN 관계를 알아보기 힘들게 되므로,
이럴 때 쓰시면 편리하실 듯 하네요. ^^
이상입니다.
Oracle START WITH ~ CONNECT BY 절 MSSQL로 처리하기.
* Oracle START WITH ~ CONNECT BY 절 MSSQL로 처리하기.
# Oracle
SELECT LEVEL, CATE_ID, LTRIM (SYS_CONNECT_BY_PATH (CATE_NAME, ' > '), ' > ') || ' > ' AS CATE_NAME
FROM TBL_CATEGORY
START WITH CATE_ID = 1
CONNECT BY PRIOR CATE_ID = PARENT_CATE_ID
# SQL Server
WITH CTE_TABLE
AS
(
SELECT 1 AS LEVEL, A.CATE_ID, PARENT_CATE_ID, CATE_NAME, CONVERT(VARCHAR(100), CAST(A.CATE_NAME as VARCHAR(100)) + ' > ') AS CATE_NAME
FROM dbo.TBL_CATEGORY A
WHERE A.CATE_ID = 1
UNION ALL
SELECT LEVEL + 1, M.CATE_ID, M.PARENT_CATE_ID, M.CATE_NAME, CONVERT(VARCHAR(100), N.CATE_NAME + ' > ' + CAST(M.CATE_NAME AS VARCHAR(100)) + ' > ' ) AS CATE_NAME
FROM dbo.TBL_CATEGORY M JOIN CTE_TABLE N ON M.PARENT_CATE_ID = N.CATE_ID
)
SELECT * FROM CTE_TABLE
;