我无法弄清楚如何返回查询结果,其中我有行值,我想将其转换为列。
简而言之,这是我在SQL Server 2008中当前架构的一个示例:
以下是我希望查询结果如下所示的示例:
以下是使用的SQLFiddle.com - http://sqlfiddle.com/#!6/6b394/1/0
有关架构的一些有用说明:
如您所见,从示例所需的最终结果图像中,将两行合并,您可以看到每个值都有自己的相关名称列。
我已经看过几个可能的例子,但不太适用于我的目的。我见过使用分组和案例方法的例子。我已经看到了PIVOT的许多用途,甚至在SQL中创建了一些自定义函数。我不确定哪种方法最适合我。我可以对此有所了解吗?
答案 0 :(得分:3)
您可以通过许多不同的方式获得结果。多个JOIN,unpivot / pivot或带聚合的CASE。
他们都有利弊,所以你需要决定哪种方法最适合你的情况。
多个连接 - 现在你已经声明每天总共有2行 - 一个用于苹果和橙色。多次加入桌面时,您需要某种列加入。该列似乎是timestamp
,但如果您有一天只能获得一行,会发生什么。然后由INNER JOIN提供@Becuzz won't work解决方案,因为它只返回每天包含两个条目的行。 LeYou可以使用FULL JOIN
使用多个JOIN,即使每天只有一个条目,也会返回数据:
select
[Timestamp] = Coalesce(a.Timestamp, o.Timestamp),
ApplesNumOffered = a.[NumOffered],
ApplesNumTaken = a.[NumTaken],
ApplesNumAbandoned = a.[NumAbandoned],
ApplesNumSpoiled = a.[NumSpoiled],
OrangesNumOffered = o.[NumOffered],
OrangesNumTaken = o.[NumTaken],
OrangesNumAbandoned = o.[NumAbandoned],
OrangesNumSpoiled = o.[NumSpoiled]
from
(
select timestamp, numoffered, NumTaken, numabandoned, numspoiled
from myTable
where FruitType = 'Apple'
) a
full join
(
select timestamp, numoffered, NumTaken, numabandoned, numspoiled
from myTable
where FruitType = 'Orange'
) o
on a.Timestamp = o.Timestamp
order by [timestamp];
见SQL Fiddle with Demo。多个连接的另一个问题是,如果您有两个以上的值,则每个值都需要一个额外的连接。
如果您的值有限,那么我建议使用聚合函数和CASE表达式来获得结果:
SELECT
[timestamp],
sum(case when FruitType = 'Apple' then NumOffered else 0 end) AppleNumOffered,
sum(case when FruitType = 'Apple' then NumTaken else 0 end) AppleNumTaken,
sum(case when FruitType = 'Apple' then NumAbandoned else 0 end) AppleNumAbandoned,
sum(case when FruitType = 'Apple' then NumSpoiled else 0 end) AppleNumSpoiled,
sum(case when FruitType = 'Orange' then NumOffered else 0 end) OrangeNumOffered,
sum(case when FruitType = 'Orange' then NumTaken else 0 end) OrangeNumTaken,
sum(case when FruitType = 'Orange' then NumAbandoned else 0 end) OrangeNumAbandoned,
sum(case when FruitType = 'Orange' then NumSpoiled else 0 end) OrangeNumSpoiled
FROM myTable
group by [timestamp];
见SQL Fiddle with Demo。甚至像@ M.Ali那样使用PIVOT/UNPIVOT。如果您有未知值,那么这些问题就会出现 - 这意味着不只是Apple
和Orange
。您将使用动态SQL来获取结果。动态SQL将创建一个需要由引擎执行的sql字符串:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(FruitType + col)
from
(
select FruitType
from myTable
) d
cross apply
(
select 'NumOffered', 0 union all
select 'NumTaken', 1 union all
select 'NumAbandoned', 2 union all
select 'NumSpoiled', 3
) c (col, so)
group by FruitType, Col, so
order by FruitType, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT TimeStamp,' + @cols + '
from
(
select TimeStamp,
new_col = FruitType+col, value
from myTable
cross apply
(
select ''NumOffered'', NumOffered union all
select ''NumTaken'', NumOffered union all
select ''NumAbandoned'', NumOffered union all
select ''NumSpoiled'', NumOffered
) c (col, value)
) x
pivot
(
sum(value)
for new_col in (' + @cols + ')
) p '
exec sp_executesql @query;
所有版本都会给出结果:
| timestamp | AppleNumOffered | AppleNumTaken | AppleNumAbandoned | AppleNumSpoiled | OrangeNumOffered | OrangeNumTaken | OrangeNumAbandoned | OrangeNumSpoiled |
|---------------------------|-----------------|---------------|-------------------|-----------------|------------------|----------------|--------------------|------------------|
| January, 01 2015 00:00:00 | 55 | 12 | 0 | 0 | 12 | 5 | 0 | 1 |
| January, 02 2015 00:00:00 | 21 | 6 | 2 | 1 | 60 | 43 | 0 | 0 |
| January, 03 2015 00:00:00 | 49 | 17 | 2 | 1 | 109 | 87 | 12 | 1 |
| January, 04 2015 00:00:00 | 6 | 4 | 0 | 0 | 53 | 40 | 0 | 1 |
| January, 05 2015 00:00:00 | 32 | 14 | 1 | 0 | 41 | 21 | 5 | 0 |
| January, 06 2015 00:00:00 | 26 | 24 | 0 | 1 | 97 | 30 | 10 | 1 |
| January, 07 2015 00:00:00 | 17 | 9 | 2 | 0 | 37 | 27 | 0 | 4 |
| January, 08 2015 00:00:00 | 83 | 80 | 3 | 0 | 117 | 100 | 5 | 1 |
答案 1 :(得分:1)
根据您的标准,将两个伴随行连接在一起并选择适当的字段似乎是最简单的答案。你可以去PIVOTs,UNIONs和GROUP BYs等路线,但这看起来有些过分。
select apples.Timestamp
, apples.[NumOffered] as ApplesNumOffered
, apples.[NumTaken] as ApplesNumTaken
, apples.[NumAbandoned] as ApplesNumAbandoned
, apples.[NumSpoiled] as ApplesNumSpoiled
, oranges.[NumOffered] as OrangesNumOffered
, oranges.[NumTaken] as OrangesNumTaken
, oranges.[NumAbandoned] as OrangesNumAbandoned
, oranges.[NumSpoiled] as OrangesNumSpoiled
from myTable apples
inner join myTable oranges on oranges.Timestamp = apples.Timestamp
where apples.FruitType = 'Apple'
and oranges.FruitType = 'Orange'
答案 2 :(得分:-1)
<强>查询强>
;WITH CTE AS
(SELECT [Timestamp]
,FruitType + EventType AS Cols
,Qty
from myTable t
UNPIVOT (Qty FOR EventType IN (NumOffered ,NumTaken
,NumAbandoned,NumSpoiled))up
)
SELECT * FROM CTE
PIVOT (SUM(Qty) FOR Cols IN (AppleNumOffered,AppleNumTaken
,AppleNumAbandoned,AppleNumSpoiled
,OrangeNumOffered, OrangeNumTaken
,OrangeNumAbandoned,OrangeNumSpoiled))p
<强>结果强>
╔═════════════════════════╦═════════════════╦═══════════════╦═══════════════════╦═════════════════╦══════════════════╦════════════════╦════════════════════╦══════════════════╗
║ Timestamp ║ AppleNumOffered ║ AppleNumTaken ║ AppleNumAbandoned ║ AppleNumSpoiled ║ OrangeNumOffered ║ OrangeNumTaken ║ OrangeNumAbandoned ║ OrangeNumSpoiled ║
╠═════════════════════════╬═════════════════╬═══════════════╬═══════════════════╬═════════════════╬══════════════════╬════════════════╬════════════════════╬══════════════════╣
║ 2015-01-01 00:00:00.000 ║ 55 ║ 12 ║ 0 ║ 0 ║ 12 ║ 5 ║ 0 ║ 1 ║
║ 2015-01-02 00:00:00.000 ║ 21 ║ 6 ║ 2 ║ 1 ║ 60 ║ 43 ║ 0 ║ 0 ║
║ 2015-01-03 00:00:00.000 ║ 49 ║ 17 ║ 2 ║ 1 ║ 109 ║ 87 ║ 12 ║ 1 ║
║ 2015-01-04 00:00:00.000 ║ 6 ║ 4 ║ 0 ║ 0 ║ 53 ║ 40 ║ 0 ║ 1 ║
║ 2015-01-05 00:00:00.000 ║ 32 ║ 14 ║ 1 ║ 0 ║ 41 ║ 21 ║ 5 ║ 0 ║
║ 2015-01-06 00:00:00.000 ║ 26 ║ 24 ║ 0 ║ 1 ║ 97 ║ 30 ║ 10 ║ 1 ║
║ 2015-01-07 00:00:00.000 ║ 17 ║ 9 ║ 2 ║ 0 ║ 37 ║ 27 ║ 0 ║ 4 ║
║ 2015-01-08 00:00:00.000 ║ 83 ║ 80 ║ 3 ║ 0 ║ 117 ║ 100 ║ 5 ║ 1 ║
╚═════════════════════════╩═════════════════╩═══════════════╩═══════════════════╩═════════════════╩══════════════════╩════════════════╩════════════════════╩══════════════════╝
<强> SQL FIDDLE
强>
答案 3 :(得分:-2)
M.Ali也打败了我。 UNPIVOT和PIVOT是您与这些类型的转换的朋友。
用UNPIVOT和PIVOT刷新记忆时,我多次使用article。