순위관련

RANK(), DENSE_RANK(), ROW_NUMBER()

설명

Rank() - 해당행에 대한 우선순위를 결정한다(중복우선순위 o)

Dense_Rank() - 해당행에 대한 우선순위를 결정한다(중복우선순위 x) 

Row_number()  - 조건을 만족한느 모든 행의 번호를 결정한다


OVER() - ORDER BY, GROUP BY 서브쿼리를 개선하기 위해 나온 함수

          - 집계함수 뒤에서 사용하며, 집계함수 외의 컬럼을 그룹으로 묶어준다.


OVER() 에 사용되는 OPTION

1. PARTITION BY : 그룹에서 파티션을 짓는다.

2. ORDER BY DESC

3. NULLS FIRST : NULL 데이터를 먼저 출력.

4. NULLS LAST : NULL 데이터를 나중에 출력.


#Temp 테이블

코드


1
2
3
4
5
SELECT V,
       RANK() OVER(ORDER BY V),
       DENSE_RANK() OVER(ORDER BY V),
       RANK() OVER(ORDER BY V)
  FROM #TEMP
cs


실행결과




OVER() 함수


COUNT(*)OVER() : 전체행 카운트

COUNT(*)OVER(PARTITION BY 컬럼) : 그룹단위로 나누어 카운트


MAX(컬럼)OVER() : 전체행 중에 최고값

MAX(컬럼)OVER(PARTITION BY 컬럼) : 그룹내 최고값


MIN(컬럼)OVER() : 전체행 중에 최소값

MIN(컬럼)OVER(PARTITION BY 컬럼) : 그룹내 최소값


SUM(컬럼)OVER() : 전체행 합

SUM(컬럼)OVER(PARTITION BY 컬럼) : 그룹내 합


AVG(컬럼)OVER() : 전체행 평균

AVG(컬럼)OVER(PARTITION BY 컬럼) : 그룹내 평균


STDDEV(컬럼)OVER() : 전체행 표준편차

STDDEV(컬럼)OVER(PARTITION BY 컬럼) : 그룹내 표준편차


RATIO_TO_REPORT(컬럼)OVER() : 현재행값/SUM(전체행값)

RATIO_TO_REPORT(컬럼)OVER(PARTITION BY 컬럼) : 현재행값 / SUM(그룹행값) 


'SQL > MS-SQL' 카테고리의 다른 글

NULL 비교하기  (0) 2017.09.19
일반집계함수 WINDOW FUNCTION  (0) 2017.09.07
트리거(Trigger)  (0) 2017.09.06
커서(Cursor)  (0) 2017.09.06
UNION ALL로 소계, 합계 구하기  (0) 2017.09.05

트리거

트리거(Trigger)란, 방아쇠를 당기다 라는 뜻인데, 방아쇠를 당기면 연쇄적으로 단계가 착착착 일어나서 최종적으로 총알이 발사 되듯이, 어떤 일이 발생하면 어떤일이 자동으로 발생되는 의미가 있다.


즉, SQL에서 트리거란 특정 테이블에 INSERT, DELETE, UPDATE가 발생했을 때 다른 이벤트를 처리하도록 하기위한 방법이다.


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATE TRIGGER [NAME_OF_TRIGGER] ON [TABLE] FOR [INSERT | DELETE | UPDATE
AS 
BEGIN
     -- INSERTED에서 USER_ID를 대입하고 싶을때
     DECLARE @USER_ID NVARCHAR(20
     SELECT @USER_ID = USER_ID FROM INSERTED 
     
     -- INSERT
     INSERT INTO ADDRESS VALUES(@USER_ID @NO_PHONE, GETDATE())
     
     -- DELETE
     SELECT * FROM DELETED
     
     --UPDATE
     UPDTAE [TABLE1] SET NO_PHONE = @NO_PHONE 
      WHERE USER_ID = @USER_ID 
END
cs


설명

MS-SQL에서는 삽입, 삭제될 행을 테이블로 관리하고있는데, 그 테이블이 INSERTED,  DELETED테이블이다.

UPDATE는 UPDATED를 사용하는것이 아니라 UPDATE는 내부적으로 DELETE후 INSERT하기 때문에 DELETED테이블과, INSERTED테이블을 사용한다.


예를 들어서 기존 값이 UPDATE되었다면, 기존 값은 DELETED에 들어가고, 새로운 값은 INSERTED에 들어가게된다.

따라서 업데이트 이전의 값과 이후의 값을 DELETED와 INSERTED 테이블을 통해서 확인할 수 있다.


'SQL > MS-SQL' 카테고리의 다른 글

일반집계함수 WINDOW FUNCTION  (0) 2017.09.07
순위관련 WINDOW FUNCTION  (0) 2017.09.07
커서(Cursor)  (0) 2017.09.06
UNION ALL로 소계, 합계 구하기  (0) 2017.09.05
CHOOSE, IIF 논리함수  (0) 2017.09.05

커서

 - 테이블에서 여러개의 행을 쿼리한 후에 쿼리의 결과인 행 집합을 한 행씩 처리하기 위한 방식이다.

 - 한행씩 읽어 나간다.

 - 임시테이블과 함께쓰면 각 테이블에서 원하는 데이터를 수집해서 원하는 테이블을 만들수 있다.


커서의 처리순서

커서 선언(DECLARE) 

커서열기(OPEN)

데이터가져오기(FETCH NEXT FROM "CURSOR_NAME" INTO 파라미터) 

WHILE(@@FETCH_STATUS = 0)

(

 데이터 처리(쿼리문) 

 데이터가져오기(FETCH NEXT FROM "CURSOR_NAME" INTO 파라미터) 

)

커서 닫기(CLOSE) 

커서해제(DEALLOCATE)


ERROR :

 오류메시지(RAISERROR(@ERRMSG,18,1))

 커서 닫기(CLOSE) 

 커서해제(DEALLOCATE)

RETURN


ERROR2 : 오류메시지(RAISERROR(@ERRMSG,18,1))


커서 예제


테스트 테이블 생성 및 데이터 입력


1
2
3
4
5
6
7
8
9
10
create table TEST(문항int, 답변자varchar(10), 답변내용int)
 
insert into test values (1,'홍길동',1)
insert into test values (1,'갑돌이',2)
insert into test values (1,'홍길동',3)
insert into test values (2,'홍길동',4)
insert into test values (3,'홍길동',1)
insert into test values (3,'홍길동',2)
insert into test values (3,'홍길동',3)
 
cs


테이블

   문항         답변자     답변내용

-----------   ----------    -----------

1    홍길동    1

1    갑돌이    2

1    홍길동    2

2    홍길동    4

3    홍길동    1

3    홍길동    2

3    홍길동    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
-- 결과를입력할임시테이블
CREATE TABLE #temp(문항 INT, 답변자 VARCHAR(10), 답변내용 VARCHAR(100))
 
 
-- 커서에 사용할 변수선언
DECLARE @V_문항 INT, @V_답변자 VARCHAR(10), @V_답변내용 INT
DECLARE @V_CNT INT, @V_복합답변 VARCHAR(100)
 
 --커서 선언
DECLARE MYCUR CURSOR FOR 
      
       SELECT 문항,답변자,답변내용
       FROM TEST
       ORDER BY 문항,답변자,답변내용
 
 --커서 열기
OPEN MYCUR
 
--첫행을 읽어서 SELECT 순서대로 변수에 대입
FETCH NEXT FROM MYCUR INTO @V_문항, @V_답변자, @V_답변내용
 
 --첫행을 에러없이 뽑았다면 @@FETCH_STATUS 는 0을 반환한다.
 --더이상 읽을 행이 없다면 WHILE문을 종료한다.
WHILE (@@FETCH_STATUS = 0)
-- 뽑은 변수를 가지고  BEGIN-END실행
BEGIN       
       SET @CNT = ISNULL((SELECT COUNT(*)  FROM #temp WHERE 문항=@V_문항 AND 답변자=@V_답변자),0)
 
       IF @CNT = 0
       BEGIN
             INSERT INTO #temp(문항,답변자,답변내용) values (@V_문항, @V_답변자, convert(varchar,@V_답변내용))
       END
       ELSE
       BEGIN
             UPDATE #temp
             SET 답변내용=답변내용+','+convert(varchar,@P_답변내용)
             WHERE 문항=@V_문항 AND 답변자=V_@답변자
       END
 
        -- 다음 행을 읽어서 변수로 대입한다.
       FETCH NEXT FROM MYCUR INTO  @V_문항, @V_답변자, @V_답변내용 
END
 
 -- 커서를 닫고, 할당을 해제한다.
CLOSE MYCUR
DEALLOCATE MYCUR
 
 
--결과가 입력된 임시테이블 조회
SELECT * FROM #TEMP ORDER BY 답변자,문항
cs



결과

   문항      답변자    답변내용

----------- ---------- -----------

1             갑돌이        2

1             홍길동        1,3

2             홍길동        4

3             홍길동        1,2,3



[참고 : http://sweeper.egloos.com/3028155]


'SQL > MS-SQL' 카테고리의 다른 글

순위관련 WINDOW FUNCTION  (0) 2017.09.07
트리거(Trigger)  (0) 2017.09.06
UNION ALL로 소계, 합계 구하기  (0) 2017.09.05
CHOOSE, IIF 논리함수  (0) 2017.09.05
특정경우를 만족하는 행 SELECT  (0) 2017.09.04


UNION ALL로 소계, 합계 구하는 법

1. 원하는 행을 SELECT한다.

2. UNION ALL

3. 소계를 구하고 싶은 컬럼을 GROUP BY 해서 SUM 한다.

4. UNION ALL

5. 합계를 구하고 ORDER BY로 SORTING한다. 



예를들어서 A~J까지의 사람이 있고

STEP에 따라서 VALUE라는 값을 부여받을때

VALUE에 대한  소계를 구하고 이에 대한 총합을 구하기 위해서는 다음과 같이 할수있다.


테이블


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SELECT  A.*
  INTO #TEMP
  FROM 
  (
    SELECT 'A' NAME, '1' STEP, 100 VALUE
    UNION ALL
    SELECT 'B' NAME, '1' STEP, 100 VALUE
    UNION ALL
    SELECT 'C' NAME, '1' STEP, 100 VALUE
    UNION ALL
    SELECT 'D' NAME, '2' STEP, 200 VALUE
    UNION ALL
    SELECT 'E' NAME, '2' STEP, 200 VALUE
    UNION ALL
    SELECT 'F' NAME, '3' STEP, 300 VALUE
    UNION ALL
    SELECT 'G' NAME, '3' STEP, 300 VALUE
    UNION ALL
    SELECT 'H' NAME, '3' STEP, 300 VALUE
    UNION ALL
    SELECT 'I' NAME, '4' STEP, 400 VALUE
    UNION ALL
    SELECT 'J' NAME, '4' STEP, 400 VALUE
  )  
cs




코드

 

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
SELECT
   A.NAME,  
   A.STEP, --기준
   A.VALUE,  
  '1' SORT   
  FROM #TEMP A  
   
 UNION ALL  
   
 SELECT   
    '소계' NAME,
    A.STEP, --기준
    SUM(VALUE),  
    '2' SORT  
      
 FROM #TEMP A  
 GROUP BY STEP  
     
   UNION ALL  
   
 SELECT 
    '합계' NAME, 
    '9999' STEP, --기준
    SUM(VALUE),  
    '3' SORT  
 FROM #TEMP A  
  
ORDER BY STEP, SORT  
cs


결과



주의할점

1.

합계행을 만들때 주의해야할 점은 STEP별로 SORT를 하기때문에 STEP에 값이 없으면 맨 위로 올라가게된다.

그래서 STEP에 값을 제일 마지막 값으로 두어야하고, 이 마지막 값보다 큰 값이 있으면 안된다.


2.

SORT를 두어서 ORDER BY시 사용하는 이유는 

ORDER BY를 쓰지않은 결과물은 다음고가 같다.




여기서 STEP으로만 정렬을 하게되면


STEP으로만 정렬되기떄문에 소계행이 맨밑으로 가지 못하는 결과가 생기게된다.


따라서 SORT를 두어서 STEP으로 먼저 정렬하고 정렬된 파티션에서 또한번 SORT로 정렬한다면 소계행이 그 파티션의 맨 밑으로 들어갈수 있게 된다.



'SQL > MS-SQL' 카테고리의 다른 글

트리거(Trigger)  (0) 2017.09.06
커서(Cursor)  (0) 2017.09.06
CHOOSE, IIF 논리함수  (0) 2017.09.05
특정경우를 만족하는 행 SELECT  (0) 2017.09.04
FOR XML  (0) 2017.09.04

SQL Server 2012 T-SQL: CHOOSE, IIF 논리함수



새롭게 제공되는 내용 중에서 CHOOSE, IIF를 한번 사용해보도록 하겠습니다.


SELECT 구문에서 조건에 따라 값을 나타내려고 할 경우 CASE WHEN 문을 사용해서 처리했습니다. CASE 구문을 작성하면 코드가 길어지고 가독성이 좀 떨어지는 측면이 있었습니다.


CHOOSE

SQL Server 2012에서는 보다 더 간결하고 쉽게 처리 가능한 CHOOSE, IIF 구문이 제공됩니다.


아래 구문을 한번 살펴보시죠~


 

1
2
3
4
5
6
7
8
9
SELECT  CASE DATEPART(WEEKDAY, GETDATE())
                                WHEN 1 THEN N'일요일'
                                WHEN 2 THEN N'월요일'
                                WHEN 3 THEN N'화요일'
                                WHEN 4 THEN N'수요일'
                                WHEN 5 THEN N'목요일'
                                WHEN 6 THEN N'금요일'
                                WHEN 7 THEN N'토요일'
                     END
cs


참고로

 SELECT DATENAME (WEEKDAY, '20130730') -- 화요일

 SELECT DATEPART (WEEKDAY, '20130730') -- 3

이다.


위 구문의 경우는 CASE WHEN 구문으로 작성한 내용인데 CHOOSE 구문으로 변경해보도록 하겠습니다. 더 간결해보입니다.


1
SELECT CHOOSE(DATEPART(WEEKDAY, GETDATE()) , 
N'일요일',N'월요일',N'화요일',N'수요일',N'목요일',N'금요일',N'토요일')
cs


CHOOSE 논리함수의 구문의 규칙은 아래와 같습니다.


CHOOSE ( index, val_1, val_2 [, val_n ] )

 

Index 는 1부터 시작하는 정수이며 val_1.., 등은 인덱스에 매치되는 임의의 데이터 형식입니다.


그러므로 1부터 반환하는 정수가 나오는 인수를 맨 처음에, 나머지는 해당 값을 정의하면 됩니다.


1
SELECT CHOOSE ( 3'Manager''Director''Developer''Tester' ) AS Result;
cs

--Developer

3이므로 세 번째에 해당하는 Developer를 반환합니다.

 


CHOOSE 논리 함수에 대한 내용은 아래 링크를 참조하십시오.


http://technet.microsoft.com/ko-kr/library/hh213019(v=sql.110).aspx 


IIF

또 다른 논리함수인 IIF 를 한번 살펴보겠습니다. 사실 IIF는 CASE 문의 약식 방법입니다. TRUE, FALSE에 따라 처리할 경우 IIF를 사용할 수 있습니다. IIF 는 SQL Server Reporting의 식에서도 사용이 되었기 때문에 사용해보았다면 적용하시는데 큰 문제 없을 것으로 보입니다.


IIF ( boolean_expression, true_value, false_value ) 

boolean_expression 이 TRUE 이면 true_value 가 반환됩니다. 


 

1
2
3
4
5
6
7
8
9
SELECT
[ProductID], [Name], [ListPrice]
, CASE WHEN [ListPrice] < 500 THEN  N'500이하'
           ELSE 
             CASE WHEN [ListPrice] < 1000 THEN N'1000이하' ELSE N'1000이상'
             END
           END AS ProceLevel
FROM [Production].[Product]
WHERE [ListPrice] >0
cs

 

500보다 작으면 ‘500이하’, 500보다 크고 1000보다 작으면 ‘1000’이하, 1000보다 크면 ‘1000’이상입니다. IIF로 변환해보겠습니다.  


1
2
3
4
5
6
7
8
9
10
11
12
SELECT
[ProductID], [Name], [ListPrice]
, IIF([ListPrice] < 500, N'500이하', IIF([ListPrice] < 1000, N'1000이하',N'1000이상')) AS ProceLevel
FROM [Production].[Product]
WHERE [ListPrice] >0  
/*
522      HL Touring Seat Assembly      196.92  500이하
680      HL Road Frame - Black, 58      1431.50 1000이상
706      HL Road Frame - Red, 58        1431.50 1000이상
707      Sport-100 Helmet, Red 34.99    500이하
708      Sport-100 Helmet, Black          34.99    500이하
*/
cs

 

위 두 구문의 실행계획을 보면 똑같습니다. 편하고 가독성 있는 구문을 쓰면 될 것 같네요~


CASE 문 보다 더 간결한 CHOOSE, IIF 논리함수에 대한 내용을 살펴보았습니다.


출처: http://redju.tistory.com/142 [redJu(홍주)]

'SQL > MS-SQL' 카테고리의 다른 글

커서(Cursor)  (0) 2017.09.06
UNION ALL로 소계, 합계 구하기  (0) 2017.09.05
특정경우를 만족하는 행 SELECT  (0) 2017.09.04
FOR XML  (0) 2017.09.04
WINDOW FUNCTION  (0) 2017.09.04

특정한 경우를 만족하는 행을 SELECT하기 위해서 WHERE 절에서


1
2
3
4
5
6
7
8
9
10
(
    CASE WHEN @CD_COMPANY = '1000' AND CODE IN ('300''310''320') THEN 1 ELSE 0 END
            WHEN @CD_COMPANY = '2000' AND CODE IN ('300' ) THEN 1 ELSE 0 END
= 1
      
 
 
(
    CASE WHEN A.CD_COMPANY = '1000' AND A.CODE IN ('100''200') THEN 1 ELSE 0 END
= 0
cs


특정한 경우를 만족하는 값만 리턴받고 싶을때


예를 들어서 

회사코드가 1000이고 CODE가 100과 200인 행은 SELECT에서 제외하고 싶을때,


회사코드가 1000이고 CODE가 300, 310, 320인 행과

회사코드가 2000이고 CODE가 300인 행만 리턴받고 싶을때



WHERE절에서 CASE WHEN절을 사용하여 해당 요구사항을 만족 시킬 수 있다.


물론 OR를 사용하여 해당문제를 해결할 수도 있지만, OR절을 사용하게 되면 INDEX가 있음에도 불구하고 FULL SCAN을 유도 하기 때문에 시간이 오래걸린다. 그래서 OR은 되도록 변수에만 사용하여야 한다.


그리고 TRUE는 1 FALSE는 0으로 정해서 가독성을 높이자.

'SQL > MS-SQL' 카테고리의 다른 글

UNION ALL로 소계, 합계 구하기  (0) 2017.09.05
CHOOSE, IIF 논리함수  (0) 2017.09.05
FOR XML  (0) 2017.09.04
WINDOW FUNCTION  (0) 2017.09.04
Dynamic Query와 Pivot  (0) 2017.09.03

FOR XML

원래는 디비와 xml을 연동하기 위해서 나온 연산자로써 FOR XML('row') 라고 SELECT절 뒤에 쓰게 되면, 반환 되어서 나오는 컬럼들이 한줄로 나열되고 <row>속성1</row><row>속성2</row>처럼 id에 감싸져서 반환되는 함수이다.





그런데 이런 일뿐 아니라 SELECT된 결과를 한행에 표현하고 싶을때에 사용해도 좋은 함수이다.


코드(간략하게)

1
2
3
4
5
6
7
8
9
10
11
12
SELECT ...
  FROM
(
    SELECT ...
 
           STUFF((
                  SELECT DISTINCT ', '+ CK1.KOR
                    FROM TBL1 CK1
                   WHERE CK1.PK = TBL1.PK 
FOR XML PATH(''))1,2,'')
    ...
     FROM TBL1 T1
)
cs


T1이 먼저 생성되기때문에 나중에 생성되는 CK1을 T1으로 필터링 해주어야 각 행마다 모두 같은 값이 안나온다.
필터링에 신경쓰자!

결과






'SQL > MS-SQL' 카테고리의 다른 글

CHOOSE, IIF 논리함수  (0) 2017.09.05
특정경우를 만족하는 행 SELECT  (0) 2017.09.04
WINDOW FUNCTION  (0) 2017.09.04
Dynamic Query와 Pivot  (0) 2017.09.03
sp_executesql  (0) 2017.09.03

WINDOW FUNCTION

행과 행간의 관계를 쉽게 정의하기 위해 만든 함수

윈도우 함수를 활용하면 복잡한 프로그램을 하나의 SQL 문장으로 쉽게 해결할 수 있다.

분석 함수(ANALYTIC FUNCTION)나 순위 함수(RANK FUNCTION)로도 알려져 있는 윈도우 함수 (ANSI/ISOSQL 표준은 WINDOW FUNCTION이란 용어를 사용함)는 데이터웨어하우스에서 발전한 기능이다.


WINDOW FUNCTION 종류

구분종류종류
순위(RANK) 관련RANK, DENSE_RANK, ROW_NUMBER대부분 지원
집계(AGGREGATE) 관련SUM, MAX, MIN, AVG, COUNTSQL Server 경우 Over절 내 Orderby 지원 못함
순서 관련 함수FIRST_VALUE, LAST_VALUE, LAG, LEADORACLE 만 지원
그룹 내 비율 관련 함수CUME_DIST, PERCENT_RANK, NTILE, RATIO_TO_REPORTPERCENT_RANK 함수는 ANSI/ISO SQL 표준과 Oracle DBMS에서 지원하고 있으며, NTILE 함수는 ANSI/ISO SQL 표준에는 없지만, Oracle, SQL Server에서 지원하고 있다. RATIO_TO_REPORT 함수는 Oracle에서만 지원되는 함수(현업에서 유용).

선형분석을 포 

CORR, COVAR_POP, COVAR_SAMP, STDDEV, STDDEV_POP, STDDEV_SAMP, VARIANCE, VAR_POP, VAR_SAMP, REGR_(LINEAR REGRESSION), REGR_SLOPE, REGR_INTERCEPT, REGR_COUNT, REGR_R2, REGR_AVGX, REGR_AVGY, REGR_SXX, REGR_SYY, REGR_SXY특화되어있으므로 생략

WINDOW FUNCTION SYNTAX

WINDOW 함수에는 OVER 문구가 키워드로 필수 포함된다.

1
2
3
4
5
6
7
8
SELECT WINDOW_FUNCTION (ARGUMENTS) OVER ( [PARTITION BY 칼럼]] [ORDER BY 절] [WINDOWING 절] )
 FROM 테이블 명;
 
 
BETWEEN 사용 타입
 ROWS | RANGE BETWEEN UNBOUNDED PRECEDING | CURRENT ROW 
| VALUE_EXPR PRECEDING/FOLLOWING AND UNBOUNDED FOLLOWING 
| CURRENT ROW | VALUE_EXPR PRECEDING/FOLLOWING
BETWEEN 미사용 타입
 ROWS | RANGE UNBOUNDED PRECEDING | CURRENT ROW | VALUE_EXPR PRECEDING


cs

WINDOW_FUNCTION : 기존에 사용하던 함수도 있고, 새롭게 WINDOW 함수용으로 추가된 함수도 있다. - ARGUMENTS (인수) : 함수에 따라 0 ~ N개의 인수가 지정될 수 있다.

PARTITION BY 절 : 전체 집합을 기준에 의해 소그룹으로 나눌 수 있다.

ORDER BY 절 : 어떤 항목에 대해 순위를 지정할 지 ORDER BY 절을 기술한다.

WINDOWING 절 : WINDOWING 절은 함수의 대상이 되는 행 기준의 범위를 강력하게 지정할 수 있다. ROWS는 물리적인 결과 행의 수를, RANGE는 논리적인 값에 의한 범위를 나타내는데, 둘 중의 하나를 선택해서 사용할 수 있다. 다만, WINDOWING 절은 SQL Server에서는 지원하지 않는다.



참고 : http://wiki.gurubee.net/pages/viewpage.action?pageId=26744104

'SQL > MS-SQL' 카테고리의 다른 글

특정경우를 만족하는 행 SELECT  (0) 2017.09.04
FOR XML  (0) 2017.09.04
Dynamic Query와 Pivot  (0) 2017.09.03
sp_executesql  (0) 2017.09.03
재귀쿼리  (0) 2017.09.02

+ Recent posts