将行值作为列返回的SQL查询 - SQL Server 2008

时间:2015-03-16 18:44:09

标签: sql sql-server sql-server-2008

我无法弄清楚如何返回查询结果,其中我有行值,我想将其转换为列。

简而言之,这是我在SQL Server 2008中当前架构的一个示例:

  

enter image description here

以下是我希望查询结果如下所示的示例:

  

enter image description here

以下是使用的SQLFiddle.com - http://sqlfiddle.com/#!6/6b394/1/0

有关架构的一些有用说明:

  • 该表每天将包含两行
  • 苹果一行,橘子一行
  • 我正在尝试将每对两行合并为一行
  • 要做到这一点,我需要将行值转换为它们自己的列,但只有[NumOffered],[NumTaken],[NumAbandoned],[NumSpoiled]的值 - 不是这两行中每一行的每一列都需要从示例
  • 可以看出,是重复的

如您所见,从示例所需的最终结果图像中,将两行合并,您可以看到每个值都有自己的相关名称列。

我已经看过几个可能的例子,但不太适用于我的目的。我见过使用分组和案例方法的例子。我已经看到了PIVOT的许多用途,甚至在SQL中创建了一些自定义函数。我不确定哪种方法最适合我。我可以对此有所了解吗?

4 个答案:

答案 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。如果您有未知值,那么这些问题就会出现 - 这意味着不只是AppleOrange。您将使用动态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;

请参阅SQL Fiddle with Demo

所有版本都会给出结果:

|                 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