集計関数なしのTSQLピボット


139

このようなテーブルがあります...

CustomerID   DBColumnName   Data
--------------------------------------
1            FirstName      Joe
1            MiddleName     S
1            LastName       Smith
1            Date           12/12/2009
2            FirstName      Sam
2            MiddleName     S
2            LastName       Freddrick
2            Date           1/12/2009
3            FirstName      Jaime
3            MiddleName     S
3            LastName       Carol
3            Date           12/1/2009

これが欲しい…

これはPIVOTを使用して可能ですか?

CustomerID  FirstName   MiddleName          LastName        Date
----------------------------------------------------------------------
1           Joe             S               Smith           12/12/2009
2           Sam             S               Freddrick       1/12/2009
3           Jaime           S               Carol           12/1/2009

回答:


102

MAXアグリゲートを使用できますが、それでも機能します。1つの値のMAX =その値。

この場合、customeridで5回自己結合し、テーブル参照ごとにdbColumnNameでフィルタリングすることもできます。うまくいくかもしれません。


1
同じ名前のコスチュームが2人いる場合、実際には機能しません
Leonardo

1
うまくいきます。DBColumnNameはメタデータであることを覚えておいてください-文字通り「CustomerID = 1 AND DBColumnName = 'FirstName'」でフィルタリングします。もちろん、これは、特定のCustomerIDに複数のFirstName行がある場合は機能しませんが、テーブルを適切に作成している場合は、CustomerIDとDBColumnNameの両方が主キーの一部です...
4AM

7
例としてのいくつかのコード/モッキングは素晴らしく、この答えを完全なものにしました。
DavidScherer

167

そうだね。でも何で !!??

   Select CustomerID,
     Min(Case DBColumnName When 'FirstName' Then Data End) FirstName,
     Min(Case DBColumnName When 'MiddleName' Then Data End) MiddleName,
     Min(Case DBColumnName When 'LastName' Then Data End) LastName,
     Min(Case DBColumnName When 'Date' Then Data End) Date
   From table
   Group By CustomerId

2
^^これでうまくいきました。PIVOTは、数値以外の値に対しては効率的ではありません。
Dienekes 2010

6
これは素晴らしい選択肢です。Pivotクエリで使用していたので、これに切り替えて、両方を実行するための実行プランを確認しました。このアプローチのコストは8%で、Pivo​​tアプローチは92%かかりました。
mafue

2
@CharlesBretana、あなたは素晴らしいです!あなたは私の魂を救った!)それが最善の解決策です。ありがとう!
Chaki_Black

3
このソリューションは本当に気に入っています。また、列にピボットデータではなく正しいデータが含まれていることも確認できます。
テネレッツァ2012

2
この作品は素晴らしい!しかし、どのように私がないようにするには-Warning: Null value is eliminated by an aggregate or other SET operation
GiddyUpHorsey

23
WITH pivot_data AS
(
SELECT customerid, -- Grouping Column
dbcolumnname, -- Spreading Column
data -- Aggregate Column
FROM pivot2 
)
SELECT customerid, [firstname], [middlename], [lastname]
FROM pivot_data
PIVOT (max(data) FOR dbcolumnname IN ([firstname],[middlename],[lastname])) AS p;

3
これは、TSQLピボットコマンドの適切な使用法を示しているため、受け入れられる答えになるはずです。
Ubercoder

1
このクエリでは、「pivot2」が元のデータが存在するテーブルの名前であることは注目に値します。また、ここでのCTEの使用は不必要です。CTEのSELECT下のステートメントは、元のテーブルの名前を指定しただけの可能性があります。
STLDev

@STLDev実際にSTLDevは、ピボットの動作方法ではありません。テーブル "pivot2"のすべての列がわかっているわけではありません。実際、OPが指定しなかった他の列がテーブルにある可能性があります。したがって、列を制限しない限り(CTEまたは派生テーブルクエリを使用して)、テーブル内のすべての列がグループ化で使用されます。言い換えると、PIVOTは何かを返しますが、期待したものは返しません。これは、70-761認定試験の詳細をカバーする概念です。
Zorkolot

2
PIVOT自体で使用されていない列によってPIVOTが自動的にグループ化されることは注目に値します。したがって、この例では[data]と[dbcolumnname]がPIVOTにあるため、すべてが[CustomerId]によってグループ化されます
Sal

9
SELECT
main.CustomerID,
f.Data AS FirstName,
m.Data AS MiddleName,
l.Data AS LastName,
d.Data AS Date
FROM table main
INNER JOIN table f on f.CustomerID = main.CustomerID
INNER JOIN table m on m.CustomerID = main.CustomerID
INNER JOIN table l on l.CustomerID = main.CustomerID
INNER JOIN table d on d.CustomerID = main.CustomerID
WHERE f.DBColumnName = 'FirstName' 
AND m.DBColumnName = 'MiddleName' 
AND l.DBColumnName = 'LastName' 
AND d.DBColumnName = 'Date' 

編集:私はこれをエディターなしで作成し、SQLを実行していません。私は、あなたがそのアイデアを理解することを願っています。


9

わかりにくい質問でごめんなさい。gbnは私を正しい軌道に乗せました。これは私が答えで探していたものです。

SELECT [FirstName], [MiddleName], [LastName], [Date] 
FROM #temp 
PIVOT
(   MIN([Data]) 
    FOR [DBColumnName] IN ([FirstName], [MiddleName], [LastName], [Date]) 
)AS p

次に、whileステートメントを使用して、上記のステートメントをvarcharとして作成し、動的SQLを使用する必要がありました。

このようなものを使う

SET @fullsql = @fullsql + 'SELECT ' + REPLACE(REPLACE(@fulltext,'(',''),')','')
SET @fullsql = @fullsql + 'FROM #temp '
SET @fullsql = @fullsql + 'PIVOT'
SET @fullsql = @fullsql + '('
SET @fullsql = @fullsql + ' MIN([Data])'
SET @fullsql = @fullsql + ' FOR [DBColumnName] IN '+@fulltext
SET @fullsql = @fullsql + ')'
SET @fullsql = @fullsql + 'AS p'

EXEC (@fullsql)

whileループを使用して@fulltextを作成し、テーブルから個別の列名を選択する必要があります。答えてくれてありがとう。


6

OPは実際にはアグリゲーションなしでピボットする必要はありませんでしたが、ここに来た人はどうやって見るのかを知るために:

SQLパラメータ化されたcteクエリ

その質問への回答には、集約なしのピボットが必要な状況が含まれるため、それを行う例がソリューションの一部です。


1

これを試して:

SELECT CUSTOMER_ID, MAX(FIRSTNAME) AS FIRSTNAME, MAX(LASTNAME) AS LASTNAME ...

FROM
(

SELECT CUSTOMER_ID, 
       CASE WHEN DBCOLUMNNAME='FirstName' then DATA ELSE NULL END AS FIRSTNAME,
       CASE WHEN DBCOLUMNNAME='LastName' then DATA ELSE NULL END AS LASTNAME,
        ... and so on ...
GROUP BY CUSTOMER_ID

) TEMP

GROUP BY CUSTOMER_ID

1

これはうまくいくはずです:

select * from (select [CustomerID]  ,[Demographic] ,[Data]
from [dbo].[pivot]
) as Ter

pivot (max(Data) for  Demographic in (FirstName, MiddleName, LastName, [Date]))as bro

1

次に、ピボットクエリの動的フィールドを作成するための優れた方法を示します。

-tmpテーブルに値を要約します

declare @STR varchar(1000)
SELECT  @STr =  COALESCE(@STr +', ', '') 
+ QUOTENAME(DateRange) 
from (select distinct DateRange, ID from ##pivot)d order by ID

---生成されたフィールドを表示

print @STr

exec('  .... pivot code ...
pivot (avg(SalesAmt) for DateRange IN (' + @Str +')) AS P
order by Decile')
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.