2012-02-22 15 views
2

PersonIDのアドレスを取得するためのクエリを作成しています。次のクエリは私のために働いていますが、2つのアドレスだけを返します。私は単一のクエリで 'n'個のアドレスを扱いたい。これを行う方法はありますか?PIVOTを使用してSelectクエリで列を動的に宣言する方法

多くのおかげで、次の表とサンプルデータを仮定し

SELECT 
    PersonID, PersonName 
    [Address1], [Address2] 
FROM 
    (
    SELECT 
    P.PersonID, 
    P.PersonName, 
    (ROW_NUMBER() OVER(PARTITION BY P.PersonID ORDER BY A.AddressID)) RowID 
    FROM tblPerson 
    INNER JOIN tblAddress AS A ON A.PersonID = P.PersonID 
) AS AddressTable 
PIVOT 
    (
    MAX(AddressID) 
    FOR RowID IN ([Address1], [Address2]) 
) AS PivotTable; 
+1

Itzik Ben-Gan(SQL Server MVP)には、動的ピボットの標準的な例があります。グーグルで試してみると、多くのリソースが見つかります。また、ここで:http://stackoverflow.com/q/2922797/112196。それにかかわらず、これを実現するには動的SQLを構築して実行する必要があります。 –

+0

可能な複製http://stackoverflow.com/questions/2209700/how-to-use-pivot-in-sql-server-2005-stored-procedure-joining-two-views –

+0

動的SQLに移動する必要があります。コンパイル時にすべてのクエリは、特定のシェイプ(つまり、特定の型を持つ名前付き列のセット)を使用して結果セットを返さなければなりません。 –

答えて

6

USE tempdb; 
GO 

CREATE TABLE dbo.tblPerson(PersonID INT, PersonName VARCHAR(255)); 

INSERT dbo.tblPerson SELECT 1, 'Bob' 
      UNION ALL SELECT 2, 'Charlie' 
      UNION ALL SELECT 3, 'Frank' 
      UNION ALL SELECT 4, 'Amore'; 

CREATE TABLE dbo.tblAddress(AddressID INT, PersonID INT, [Address] VARCHAR(255)); 

INSERT dbo.tblAddress SELECT 1,1,'255 1st Street' 
      UNION ALL SELECT 2,2,'99 Elm Street' 
      UNION ALL SELECT 3,2,'67 Poplar Street' 
      UNION ALL SELECT 4,2,'222 Oak Ave.' 
      UNION ALL SELECT 5,1,'36 Main Street, Suite 22' 
      UNION ALL SELECT 6,4,'77 Sicamore Ct.'; 

次のクエリは、あなたが望む結果を取得し、それは0、1またはnのアドレスをどのように処理するかを示しています。この場合、最も高い数字は3ですが、好きな場合はサンプルデータを少し調整して、より多くのアドレスでプレイできます。

DECLARE @col NVARCHAR(MAX) = N'', 
     @sel NVARCHAR(MAX) = N'', 
     @from NVARCHAR(MAX) = N'', 
     @query NVARCHAR(MAX) = N''; 

;WITH m(c) AS 
(
    SELECT TOP 1 c = COUNT(*) 
    FROM dbo.tblAddress 
    GROUP BY PersonID 
    ORDER BY c DESC 
) 
SELECT @col = @col + ',[Address' + RTRIM(n.n) + ']', 
    @sel = @sel + ',' + CHAR(13) + CHAR(10) + '[Address' + RTRIM(n.n) + '] = x' 
     + RTRIM(n.n) + '.Address', 
    @from = @from + CHAR(13) + CHAR(10) + ' LEFT OUTER JOIN xMaster AS x' 
     + RTRIM(n.n) + ' ON x' + RTRIM(n.n) + '.PersonID = p.PersonID AND x' 
     + RTRIM(n.n) + '.rn = ' + RTRIM(n.n) 
FROM m CROSS JOIN (SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id]) 
    FROM sys.all_columns) AS n WHERE n.n <= m.c; 

SET @query = N';WITH xMaster AS 
(
    SELECT PersonID, Address, 
    rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address) 
    FROM dbo.tblAddress 
) 
SELECT PersonID, PersonName' + @col 
+ ' FROM 
    (
     SELECT p.PersonID, p.PersonName, ' + STUFF(@sel, 1, 1, '') 
+ CHAR(13) + CHAR(10) + ' FROM dbo.tblPerson AS p ' + @from + ' 
) AS Addresses;'; 

PRINT @query; 
--EXEC sp_executesql @query; 

あなたがSQLを印刷する場合は、このような結果が表示されます:あなたはそれを実行する場合は、この表示されます

;WITH xMaster AS 
(
    SELECT PersonID, Address, 
    rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address) 
    FROM dbo.tblAddress 
) 
SELECT PersonID, PersonName,[Address1],[Address2],[Address3] FROM 
    (
     SELECT p.PersonID, p.PersonName, 
[Address1] = x1.Address, 
[Address2] = x2.Address, 
[Address3] = x3.Address 
FROM dbo.tblPerson AS p 
LEFT OUTER JOIN xMaster AS x1 ON x1.PersonID = p.PersonID AND x1.rn = 1 
LEFT OUTER JOIN xMaster AS x2 ON x2.PersonID = p.PersonID AND x2.rn = 2 
LEFT OUTER JOIN xMaster AS x3 ON x3.PersonID = p.PersonID AND x3.rn = 3 
) AS Addresses; 

を:

enter image description here

を私が取得するクエリを知っていますここでは醜い混乱ですが、あなたの要件はそれを指示します。私のコメントで示唆したようにカンマで区切ったリストを返すほうが簡単で、プレゼンテーション層にピボットを処理させる方が簡単です。

+1

+1スポットあり....ありがとう@Aaron Bertrand – Scorpion

関連する問題