我为提交关于这个主题的另一个问题而道歉,但我已经阅读了很多这方面的答案,我似乎无法让它为我工作。
我需要加入三个表并提取信息。其中一个表只有3列并垂直存储数据。我想将这些数据转换为横向格式。
如果我只是加入并拉动,数据将如下所示:
SELECT
a.app_id,
b.field_id,
c.field_name,
b.field_value
FROM table1 a
JOIN table2 b ON a.app_id = b.app_id
JOIN table3 c ON b.field_id = c.field_id --(table3 is a lookup table for field names)
结果:
app_id | field_id | field_name | field_value
-----------------------------------------------------
1234 | 101 | First Name | Joe
1234 | 102 | Last Name | Smith
1234 | 105 | DOB | 10/15/72
1234 | 107 | Mailing Addr | PO BOX 1234
1234 | 110 | Zip | 12345
1239 | 101 | First Name | Bob
1239 | 102 | Last Name | Johnson
1239 | 105 | DOB | 12/01/78
1239 | 107 | Mailing Addr | 1234 N Star Ave
1239 | 110 | Zip | 12456
相反,我希望它看起来像这样:
app_id | First Name | Last Name | DOB | Mailing Addr | Zip
--------------------------------------------------------------------------
1234 | Joe | Smith | 10/15/72 | PO BOX 1234 | 12345
1239 | Bob | Johnson | 12/01/78 | 1234 N Star Ave | 12456
在过去,我只是在我的数据中查找我需要的所有field_id,并为每个创建CASE语句。用户使用的应用程序包含多个产品的数据,每个产品包含不同的字段。考虑到支持的产品数量和每个产品的字段数量(许多,比我上面显示的基本示例多得多),需要很长时间才能查找并写出大量的CASE语句。
我想知道是否有一些作弊代码可以实现我的需要,而无需查看field_ids并写出来。我知道PIVOT功能可能是我正在寻找的,但是,我似乎无法让它正常工作。
认为你们可以帮忙吗?
答案 0 :(得分:30)
您可以使用PIVOT函数将数据行转换为列。
您的原始查询可用于检索所有数据,我将对其进行的唯一更改是排除列b.field_id
,因为这将改变结果的最终显示。
如果您有一个已知的field_name
值列表要转换为列,那么您可以对查询进行硬编码:
select app_id,
[First Name], [Last Name], [DOB],
[Mailing Addr], [Zip]
from
(
SELECT
a.app_id,
c.field_name,
b.field_value
FROM table1 a
INNER JOIN table2 b
ON a.app_id = b.app_id
INNER JOIN table3 c
ON b.field_id = c.field_id
) d
pivot
(
max(field_value)
for field_name in ([First Name], [Last Name], [DOB],
[Mailing Addr], [Zip])
) piv;
但是如果你要为field_name
设置一个未知数量的值,那么你需要实现动态SQL来获得结果:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(Field_name)
from Table3
group by field_name, Field_id
order by Field_id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT app_id,' + @cols + '
from
(
SELECT
a.app_id,
c.field_name,
b.field_value
FROM table1 a
INNER JOIN table2 b
ON a.app_id = b.app_id
INNER JOIN table3 c
ON b.field_id = c.field_id
) x
pivot
(
max(field_value)
for field_name in (' + @cols + ')
) p '
execute sp_executesql @query;
见SQL Fiddle with Demo。这两个都会产生结果:
| APP_ID | FIRST NAME | LAST NAME | DOB | MAILING ADDR | ZIP |
------------------------------------------------------------------------
| 1234 | Joe | Smith | 10/15/72 | PO Box 1234 | 12345 |
| 1239 | Bob | Johnson | 12/01/78 | 1234 N Star Ave | 12456 |
答案 1 :(得分:3)
试试这个
SELECT
[app_id]
,MAX([First Name]) AS [First Name]
,MAX([Last Name]) AS [Last Name]
,MAX([DOB]) AS [DOB]
,MAX([Mailing Addr]) AS [Mailing Addr]
,MAX([Zip]) AS [Zip]
FROM Table1
PIVOT
(
MAX([field_value]) FOR [field_name] IN ([First Name],[Last Name],[DOB],[Mailing Addr],[Zip])
) T
GROUP BY [app_id]
答案 2 :(得分:0)
bluefeet的答案对我来说是正确的,但我需要在列列表上有所不同:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT Distinct ',' + QUOTENAME(Field_name)
from Table3
group by field_name, Field_id
order by ',' + QUOTENAME(Field_name)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT app_id,' + @cols + '
from
(
SELECT
a.app_id,
c.field_name,
b.field_value
FROM table1 a
INNER JOIN table2 b
ON a.app_id = b.app_id
INNER JOIN table3 c
ON b.field_id = c.field_id
) x
pivot
(
max(field_value)
for field_name in (' + @cols + ')
) p '
execute sp_executesql @query;
答案 3 :(得分:0)
SQL Pivot的使用
SELECT [Id], [FirstName], [LastName], [Email]
FROM
(
SELECT Id, Att_Id, Att_Value FROM VerticalTable
) as source
PIVOT
(
MAX(Att_Value) FOR Att_Id IN ([FirstName], [LastName], [Email])
) as target
答案 4 :(得分:0)
这将解决使用group by和MAX函数,而不是数据透视:
SELECT PK_ID, MAX(PHONE) AS PHONE, MAX(MAIL) AS MAIL
FROM (
SELECT
PK_ID,
CASE
WHEN CONTACT_ALIAS.CONTACT_TYPE = 'COMPANY' THEN CONTACT_ALIAS.CONTACT_VALUE
END AS PHONE ,
CASE
WHEN CONTACT_ALIAS.CONTACT_TYPE = 'BUSINESS' THEN CONTACT_ALIAS.CONTACT_VALUE
END AS MAIL
FROM T_CONTACT_EMPLOYERS CONTACT_ALIAS
WHERE CONTACT_ALIAS.CONTACT_TYPE IN ('COMPANY' , 'BUSINESS')
) TEMP
GROUP BY PK_ID