【问题标题】:SQL to convert distinct item in row to columnSQL将行中的不同项目转换为列
【发布时间】:2017-11-11 01:58:38
【问题描述】:

我有一张桌子

Date          Item          Quantity
20170101      Mango         5
20170101      Orange        6
20170102      Mango         7
20170102      Orange        8

我想要下面的输出

Date        Mango       Orange
20170101    5           6
20170102    7           8

为此我在下面使用了 sql 查询

SELECT 
   Date,
   SUM(case when Item='Mango' then Quantity else 0 end) AS Mango,
   SUM(case when Item='Orange' then Quantity else 0 end) AS Orange
FROM orderTable
GROUP BY date

但这对于 Mango 和 Orange 来说是一种硬编码。如果我需要 orderTable 中的新项目怎么办。任何人都可以建议我如何使这个查询动态化。因此,如果我添加新项目,它会自动创建以项目名称为名称的新库,并且当未为该项目下订单时,它将在列下相对于日期的值为 0。

喜欢

Date          Item          Quantity
20170101      Mango         5
20170101      Orange        6
20170102      Mango         7
20170102      Orange        8
20170102      Cherry        9

那么输出应该是...

Date        Mango       Orange    Cherry
20170101    5           6         0
20170102    7           8         9

【问题讨论】:

  • 如果一个苹果突然出现在表格中,你想要另一列吗?您使用的是哪个 dbms?
  • 是的,MS SQL Server
  • 尝试使用枢轴功能

标签: sql sql-server tsql pivot


【解决方案1】:
IF OBJECT_ID('Test') IS NOt NUll
DROP TABLE Test

CREATE TABLE Test
(
    Date VARCHAR(100),
    Item VARCHAR(100),
    Quantity INT
)

INSERT Test VALUES
    ('20170101', 'Mango', 5),
    ('20170101', 'Orange', 6),
    ('20170102', 'Mango', 7),
    ('20170102', 'Orange', 8),
    ('20170102', 'Cherry', 9)

DECLARE @SQL AS VARCHAR(MAX)
DECLARE @Columns AS VARCHAR(MAX)
DECLARE @Columns2 AS VARCHAR(MAX)

SELECT @Columns = COALESCE(@Columns + ',','') + QUOTENAME(Item)
FROM (SELECT DISTINCT Item FROM Test) AS B
ORDER BY B.Item

SELECT @Columns2 = COALESCE(@Columns2 + ',','') + 'ISNULL(' + QUOTENAME(Item) + ', 0) AS ' + Item
FROM (SELECT DISTINCT Item FROM Test) AS B
ORDER BY B.Item

SET @SQL = '
WITH PivotData AS
(
    SELECT Date, Item, Quantity FROM Test
)
SELECT
    Date, ' + @Columns2 + '
FROM PivotData
PIVOT
(
    SUM(Quantity)
    FOR Item
    IN (' + @Columns + ')
) AS PivotResult
ORDER BY Date'

EXEC(@SQL);

DROP TABLE Test

结果:

Date        Cherry  Mango   Orange
20170101    0       5       6
20170102    9       7       8

参考(代码图片未显示,但如果您查看页面源代码,您可以访问它): http://sqlmag.com/t-sql/pivoting-dynamic-way

【讨论】:

    【解决方案2】:
    IF OBJECT_ID('Tempdb..#Temp') IS NOt NUll
    Drop Table #Temp
    
    ;With cte([Date] ,Item ,Quantity)
    AS
    (
    SELECT '20170101','Mango'  ,5 Union all
    SELECT '20170101','Orange' ,6 Union all
    SELECT '20170102','Mango'  ,7 Union all
    SELECT '20170102','Orange' ,8 Union all
    SELECT '20170102','Cherry' ,9
    )
    SELECT * INTO #Temp FROM cte
    
    DECLARE @dynamicCol nvarchar(max),
            @Sql nvarchar(max),
            @dynamicCol2 nvarchar(max)
    
    SELECT @dynamicCol=STUFF((SELECT DISTINCT ', ' + 'ISNULL('+Item +',''0'')  AS '+ Item  FROM  #Temp
    FOR XML PATH('')),1,1,'')
    
    SELECT @dynamicCol2=STUFF((SELECT DISTINCT ', ' + Item  FROM  #Temp
    FOR XML PATH('')),1,1,'')
    
    
    SET @Sql='
                SELECT [Date] , '+ @dynamicCol +' From
                (
                SELECT [Date] ,Item ,Quantity From
                #temp
                )AS Src
                PIVOT 
                (
                MAX([Quantity]) For [Item ] IN ('+@dynamicCol2+')
                )
                AS Pvt
                '
    
    PRINT @Sql
    
    EXEC(@Sql)
    

    输出

    Date        Cherry  Mango   Orange
    ----------------------------------
    20170101     0       5       6
    20170102     9       7       8
    

    【讨论】:

      【解决方案3】:
      DECLARE @cols AS NVARCHAR(MAX),
          @query  AS NVARCHAR(MAX);
      
      select @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.Item) 
                  FROM dbo.OrderTable c
                  FOR XML PATH(''), TYPE
                  ).value('.', 'NVARCHAR(MAX)') 
              ,1,1,'')
      
      set @query = 'SELECT DateOrdered, ' + @cols + ' from 
                  (
                      select Item, DateOrdered, Quantity
                      from dbo.OrderTable
                 ) x
                  pivot 
                  (
                       Sum(Quantity)
                      for Item in (' + @cols + ')
                  ) p '
      execute(@query)
      

      如果你这样做,它会给你想要的结果

      【讨论】:

        【解决方案4】:

        试试这个:

        CREATE TABLE [dbo].[test](
            [Date] [int] NULL,
            [Item] [nvarchar](50) NULL,
            [Quantity] [int] NULL
        ) ON [PRIMARY]
        
        GO
        INSERT [dbo].[test] ([Date], [Item], [Quantity]) VALUES (20170101, N'Mango', 5)
        GO
        INSERT [dbo].[test] ([Date], [Item], [Quantity]) VALUES (20170101, N'Orange', 6)
        GO
        INSERT [dbo].[test] ([Date], [Item], [Quantity]) VALUES (20170102, N'Mango', 7)
        GO
        INSERT [dbo].[test] ([Date], [Item], [Quantity]) VALUES (20170102, N'Orange', 8)
        GO
        INSERT [dbo].[test] ([Date], [Item], [Quantity]) VALUES (20170102, N'Cherry', 5)
        GO
        INSERT [dbo].[test] ([Date], [Item], [Quantity]) VALUES (20170103, N'Cherry', 2)
        GO
        

        动态sql:

        DECLARE @cols AS NVARCHAR(MAX),
            @query  AS NVARCHAR(MAX)
        
        select @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(Item) 
                            from test
                    FOR XML PATH(''), TYPE
                    ).value('.', 'NVARCHAR(MAX)') 
                ,1,1,'')
        
        set @query = N'SELECT DATE, ' + @cols + N' from 
                     (
                        select Date,Item, Quantity from test
                    ) x
                    pivot 
                    (
                        max(Quantity)
                        for Item in (' + @cols + N')
                    ) p '
        
        exec sp_executesql @query;
        

        结果:

        DATE       Cherry   Mango   Orange
        20170101    NULL    5       6
        20170102    5       7       8
        20170103    2      NULL     NULL
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-08-12
          • 1970-01-01
          • 1970-01-01
          • 2012-01-16
          • 2020-04-28
          • 2011-10-04
          相关资源
          最近更新 更多