2011-10-19 2 views
9

SQL Server (T-sql)에서 동적 열이있는 pvots를 사용하여 SQL 쿼리를 작성하고 있습니다. 긴 검색어를 제출하는 대신 간단한 모델을 사용하여 문제를 설명하고 있습니다. SQL Server에서 동적 열을 사용하는 피벗

나는 2 개 테이블 생성 : 표 1과 표 2를 다음과 같이 몇 가지 항목으로 그들을 채울 :

표 1 :


Col_ID1을 ............ ... COL_NAME

1 ......................... 1 월 11

2 ........ ................. Feb-11

3 ......................... 3 월 11

표 2 :


Col_ID2 ...... 계정 ..... 계정 이름 ...... 금액

1 ............... 121 ......... .. 전기 ............ 10000

2 ............... 121 ........... 전기. ........... 20000

3 ............... 121 ............ 전기 ............ 30000

1 ............... 122 ........... 전화 .............. 100

2. .............. 122 ........... 전화 .............. 200

3 ... ............ 122 ........... 전화 .............. 300

나는 피벗 (Pivot). 그러나 열 이름을 매개 변수로 생성해야합니다. creen), 하드 코딩되지 않았습니다.

쿼리는 아래 잘 작동하지만, FOLL으로 단지 몇 열을 제공합니다

1 월 11 ........... 2 월 11 ........ ... 3 월 11

10,000.00 ...... 20,000.00 ...... 30,000.00

100.00 ............... 200.00 .... ....... 300.00

나는 foll :와 같이 설명 열을 반환하는 쿼리도 원한다.

계정 ........... 계정 이름 ........... 1 월 11 일 ............ 2 월 11 일 .. ............ Mar-11

121 ................. 전기 ............ ...... 10,000.00 ...... 20,000.00 .......... 30,000.00

122 ................. 전화 .. ................... 100.00 ........... 200.00 ............. 300.00

아무도 내 목표를 달성 할 수 있도록 내 쿼리 수정을 도와 줄 수 있습니까?

이 쿼리는 http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx

누군가가 코드가 주입 공격의 대상이 될 수 있음을 언급하고 QUOTENAME 기능을 사용하는 대신 대괄호을 연결하기 위해 제안 된 2007 년 9 월과 11 월 박사 안드라스 쓴 다음 문서의 적응이다 .

내 쿼리에 Quotename을 사용하는 방법을 설명해 주시겠습니까?

고마워,

리밍 .
.
. ----------

------------------------이 & 채우기 표를 만듭니다

여기 내 쿼리 ----------------------

CREATE TABLE Table1 
(Col_ID1 INT, 
Col_Name varchar(10)) 

INSERT INTO Table1 VALUES (1, 'Jan-11') 
INSERT INTO Table1 VALUES (2, 'Feb-11') 
INSERT INTO Table1 VALUES (3, 'Mar-11') 

--------------------- ---- 만들기 & 채우기 table2 ----------------------------------

CREATE TABLE Table2 
(Col_ID2 INT, 
Account varchar(10), 
AccountName varchar(20), 
Amount numeric(18,6)) 

INSERT INTO Table2 VALUES (1, 121, 'Electricity', 10000) 
INSERT INTO Table2 VALUES (2, 121, 'Electricity', 20000) 
INSERT INTO Table2 VALUES (3, 121, 'Electricity', 30000) 
INSERT INTO Table2 VALUES (1, 122, 'Telephone', 100)   
INSERT INTO Table2 VALUES (2, 122, 'Telephone', 200) 
INSERT INTO Table2 VALUES (3, 122, 'Telephone', 300) 

- --------------------------------- 열 제목 만들기 -------------- -----

DECLARE @cols NVARCHAR(2000) 
SELECT @cols = STUFF((SELECT DISTINCT TOP 100 PERCENT 
'],[' + t2.Col_Name 
FROM Table1 AS t2 
ORDER BY '],[' + t2.Col_Name 
FOR XML PATH('') 
), 1, 2, '') + ']' 

------------------------------------ create @query --- -------------------

DECLARE @query NVARCHAR(4000) 

SET @query = N'SELECT '+ 
@cols +' 

FROM 

------------------------ --subquery -----

(SELECT
t1.Col_Name,
t2.Account,
t2.Amount
FROM Table1 AS t1
JOIN Table2 AS t2 ON t1.Col_ID1 = t2.Col_ID2
) p

-------------------- 피봇 ------------ -------------

PIVOT
(
Sum ([Amount])
FOR Col_Name IN
('+
@cols +')
) AS pvt '

---------------------- 간부 & 드롭 ----------

EXECUTE(@query) 
drop table table1 
drop table table2 

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

안녕하세요 Philip,

답장을 보내 주셔서 대단히 감사합니다.

제안 된 쿼리가 원활하게 작동하고 예상되는 화면이 생성되지만 정확히 원하는 것은 아닙니다.

첫째, 코드에 대한 감사 : SELECT @cols = ISNULL (@cols + '', '') + '['+ COL_NAME + ']'

그것은 간단하고 내 라인을 대체 않습니다 물건과 XML 경로가 포함되어 있습니다. 분명히 동일한 효과가 있습니다.

제가하고 싶은 것을 설명하겠습니다.

Sap Business 1 (회계 패키지 - 또는 ERP라고 함)에서 쿼리를 개발하고 싶습니다. Sap은 Microsoft Server 2008에서 T-SQL을 사용하며 자체 쿼리 생성기를 사용합니다. 거의 예외는 있지만 Sap sql은 T-sql과 유사합니다.

12 개월 동안 모든 수입과 지출 목록을 월별로 제공하고 싶습니다.

1 월 11 일, 2 월 11, Mar-을 (이 수시로 내 쿼리를 수정하라고 요구로) 다음과 같이

그러나, 나는 나의 열 머리글이 하드 코딩되고 싶지 않아 12 월 11 일

대신 입력란에 사용자가 입력 한 날짜부터 열 머리글을 동적으로 생성하고 싶습니다.

앞서 언급했듯이 포럼에 게시 한 쿼리는 실제 쿼리가 지나치게 단순화 된 버전으로 일러스트레이션에만 사용됩니다. 실제 검색어에는 여러 변수가 포함되어 있으며 Sap b1의 검색어 - 선택 기준 상자라는 입력 화면을 통해 사용자는 날짜를 입력 할 수 있습니다. 이 날짜는 동적으로 열 이름을 결정하는 데 사용됩니다. 내가 피벗 등 @cols, @query, 같은 복잡한 도구를 필요로하는 이유

입니다

I 입력, '01는 .06.11 '(2011 6월 1일) 입력 화면에서,이 날짜가 될 것입니다 말한다면 foll :

Jun-11, Jul-11, Aug-11 ..... 5 월 12 일과 같이 열 머리글의 이름을 결정하는 sql로 전달됩니다.

I 입력을 다른 날짜는 '01 .09.10 '(2010 9월 1일가) 열 제목이 변경됩니다 말하는 경우에 :

9 월 - 10, 10 월 10, .... 월 - 11

내 열 제목을 하드 코드 한 것으로 보입니다.

내 쿼리를 다시 살펴보고 하드 코딩되지 않고 파라 메트릭하게 열 이름을 생성 할 수있는 방법을 제안 할 수 있습니까? 그 열을 추가

감사

리밍

답변

11

은 매우 간단합니다. 마지막 쿼리는 t2.AccountName가 하위 쿼리에 추가 한

SELECT Account, AccountName, [Feb-11],[Jan-11],[Mar-11] FROM 
(SELECT 
t1.Col_Name, 
t2.Account, 
t2.AccountName, 
t2.Amount 
FROM Table1 AS t1 
JOIN Table2 AS t2 ON t1.Col_ID1 = t2.Col_ID2 
) p 
PIVOT 
(
Sum ([Amount]) 
FOR Col_Name IN 
([Feb-11],[Jan-11],[Mar-11]) 
) AS pvt 

될 것이며, 계정 및 계정 이름은 초기 SELECT에 추가됩니다. 빌드 문에 그들을 던져하면됩니다 :

SQL 주입, 나는 사람이 어떻게 든 Table1.Col_Name 내에서 악성 코드를 내장하는 경우 발생하는 것을 볼 수있는 유일한 방법에 관해서는
DECLARE @query NVARCHAR(4000) 
SET @query = N'SELECT Account, AccountName, ' + @cols +' FROM 

(SELECT 
t1.Col_Name, 
t2.Account, 
t2.AccountName, 
t2.Amount 
FROM Table1 AS t1 
JOIN Table2 AS t2 ON t1.Col_ID1 = t2.Col_ID2 
) p 

PIVOT 
(
Sum ([Amount]) 
FOR Col_Name IN 
('+ 
@cols +') 
) AS pvt ' 

, 당신은 걱정할 필요가있는 경우 그것에 대해,이 동적 쿼리를 "잠그는"것보다 더 큰 문제가 있습니다.

또한 언급할만한 가치가있어, XML을 좋아하지 않기 때문에 다음과 같이 열 목록 (@Cols)을 작성하는 것이 더 쉽고 읽기 쉽기 때문에 다음을 사용합니다.

DECLARE @cols NVARCHAR(2000)  
SELECT @cols = isnull(@cols + ',', '') + '[' + Col_Name + ']' 
FROM Table1 
ORDER BY Col_Name 
+0

안녕하세요 Philip, 귀하의 회신에 질문을 올렸습니다. Thanks Leon –

+0

이것은 정말 좋은 답변입니다 !!! – jTC

+0

''[ '+ Col_Name +'] ''대신'quotename (Col_Name)'을 사용하십시오. – jnm2

1

다른 답변을 추가하면 편집이 거의 두 번째 질문이기 때문에. (세부 사항이나 세부 사항이 없으면 일반적인 윤곽선과 psuedo 코드 만 제공 할 수 있습니다. SAP를 모르겠습니다.)

피벗부터 시작하겠습니다. 그것은 당신이 예제에서 Table1.Col_Name, varchar (10); 이러한 값은 추출되어 동적으로 열 이름으로 피벗 쿼리에 추가됩니다. 데이터베이스에 이러한 열이 없으면 사용자가 입력 한 데이터를 기반으로 쿼리를 구성해야합니다. 다음과 같은 가정하에 작업하겠습니다 : - 데이터에 날짜 시간 열이 있습니다. 여기서 값은 1 년에서 밀리 초까지입니다. - 사용자가 "시작 날짜"를 지정합니다 (항상 한 달에 한 번)? 그리고 당신은 그 다음 11 개월 동안 각 목표 월 내에 속하는 데이터를 모아서 컬럼을 생성해야합니다.

1 단계, 내가 설정하고 12 목표 컬럼이 포함 된 임시 테이블을 채우는 것 : 당신이 그것을 표시 할

CREATE TABLE #Months 
(
    Col_Name varchar(10) 
    ,MonthStart datetime 
    ,MonthEnd datetime 
) 

라벨 포맷을 MonthStart은 (달의 절대 시작이 될 것입니다 2011 년 10 월 1 일 00 : 00 : 00.000), MonthEnd가 다음 달의 절대 시작일 것입니다 (2011 년 11 월 1 일 00 : 00 : 00.000). SELECT … from <table> where DataDate >= MontStart and DataDate < MonthEnd을 사용하면 해당 월의 모든 데이터를 가져올 수 있습니다.

다음, 데이터 테이블 및 집계, 같은에서이 테이블을 조인

SELECT 
    mt.Col_Name 
    ,sum(dt.RawData) Amount 
from #Months mt 
    inner join MyData dt 
    on dt.DataDate >= mt.MonthStart 
    and dt.DataDate < mt.MonthEnd -- Yes, ON clauses don't have to be simple equivalencies! 
    inner join <other tables as necessary for Account, AccountName, etc.> 

플러그인이있는 피벗 문 안쪽의 쿼리, 추출/사용하여 임시 테이블에서 Col_Names의 목록을 작성할로 비 XML 쿼리 (나는 그 밖에 무엇을 호출해야할지 모르겠다.)를 동적으로 구현하고 실행해야한다.

+0

감사합니다 필립 레온 라이 –