0

这是在 SQL Server 2008 上运行的。

无论如何,我有销售数据,我可以编写一个查询来让输出看起来像这样:

id | Name       | Period  | Sales
1  | Customer X | 2013/01 | 50
1  | Customer X | 2013/02 | 45

目前,运行这些数据后,我正在重新排列后面代码中的数据,以便最终输出如下所示:

id  | Name       | 2013/01 | 2013/02
1   | Customer X |   50    |   40

问题是:

  1. 日期 (YYYY/MM) 范围是来自用户的输入。
  2. 如果用户选择更多输出(例如,地址和与该客户相关的大量其他可能字段),则该信息将在每一行中重复。当您在 5 年以上的时间里为 50000 多个用户执行每行 10-15 个项目时,这会导致内存不足的问题,而且效率也很低。

我考虑只提取必要的数据(客户 ID——它们是如何连接在一起的、期间和销售数据),然后在运行单独的查询以获取附加数据之后。虽然这看起来效率不高,但这是一种可能性。

另一个,我认为应该是最好的选择,是重写我的查询以继续执行我当前的代码正在执行的操作,并将数据组合在一起,这样客户数据就不会被复制并且我不会移动很多不必要的数据。

为了更好地说明我正在使用的内容,让我们假设这些表:

地址

id | HouseNum | Street | Unit | City | State

顾客

id | Name | 

销售量

id | Period | Sales

所以我想在客户 ID 上加入这些表,显示所有地址数据,假设用户输入“2012/01 -- 2012/12”,我可以将其转换为 2012/01、2012/02 ... 2012/12 在我的代码后面输入到查询执行之前,所以我有可用的。

我希望它看起来像:

id | Name | HouseNum | Street   | City | State | 2012/01 | 2012/02 | ... | 2012/12
1  | X    | 100      | Main St. | ABC  | DEF   |   30    |         | ... |   20

(该客户在 2012/02 没有销售数据——如果任何数据为空白,我希望它是空白字符串“”,而不是 NULL)

我意识到我可能无法以最好的方式解释这一点,所以请告诉我,我会添加更多信息。谢谢!

编辑:哦,最后一件事。是否可以在末尾添加一个 Min、Max、Avg 和 Total 列,它们汇总了所有透视数据?在后面的代码上做这件事没什么大不了的,但是 sql server 可以为我做的越多越好,imo!

编辑:还有一个,时间段在表格中为“2013/01”等,但我想将它们重命名为“2013 年 1 月”等,如果不是太复杂的话?

4

1 回答 1

2

您可以实现 PIVOT 函数将数据从行转换为列。您可以使用以下方法获得结果:

select id,
  name,
  HouseNum,
  Street,
  City,
  State,
  isnull([2013/01], 0) [2013/01], 
  isnull([2013/02], 0) [2013/02], 
  isnull([2012/02], 0) [2012/02], 
  isnull([2012/12], 0) [2012/12],
  MinSales,
  MaxSales,
  AvgSales,
  TotalSales
from
(
  select c.id,
    c.name,
    a.HouseNum,
    a.Street,
    a.city,
    a.state,
    s.period,
    s.sales,
    min(s.sales) over(partition by c.id) MinSales,
    max(s.sales) over(partition by c.id) MaxSales,
    avg(s.sales) over(partition by c.id) AvgSales,
    sum(s.sales) over(partition by c.id) TotalSales
  from customer c
  inner join address a
    on c.id = a.id
  inner join sales s
    on c.id = s.id
) src
pivot
(
  sum(sales)
  for period in ([2013/01], [2013/02], [2012/02], [2012/12])
) piv;

请参阅SQL Fiddle with Demo

如果您有未知数量的period值要转换为列,则必须使用动态 SQL 来获取结果:

DECLARE @cols AS NVARCHAR(MAX),
    @colsNull AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(period) 
                    from Sales
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

select @colsNull = STUFF((SELECT distinct ', IsNull(' + QUOTENAME(period) + ', 0) as '+ QUOTENAME(period) 
                    from Sales
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT id,
                name,
                HouseNum,
                Street,
                City,
                State,' + @colsNull + ' ,
                MinSales,
                MaxSales,
                AvgSales,
                TotalSales
             from 
             (
               select c.id,
                c.name,
                a.HouseNum,
                a.Street,
                a.city,
                a.state,
                s.period,
                s.sales,
                min(s.sales) over(partition by c.id) MinSales,
                max(s.sales) over(partition by c.id) MaxSales,
                avg(s.sales) over(partition by c.id) AvgSales,
                sum(s.sales) over(partition by c.id) TotalSales
              from customer c
              inner join address a
                on c.id = a.id
              inner join sales s
                on c.id = s.id
            ) x
            pivot 
            (
                sum(sales)
                for period in (' + @cols + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo。这些给出了结果:

| ID |       NAME | HOUSENUM |    STREET |    CITY |  STATE | 2012/02 | 2012/12 | 2013/01 | 2013/02 | MINSALES | MAXSALES | AVGSALES | TOTALSALES |
---------------------------------------------------------------------------------------------------------------------------------------------------
|  1 | Customer X |      100 | Maint St. |     ABC |    DEF |       0 |      20 |      50 |      45 |       20 |       50 |       38 |        115 |
|  2 | Customer Y |      108 |   Lost Rd | Unknown | Island |      10 |       0 |       0 |       0 |       10 |       10 |       10 |         10 |
于 2013-04-19T20:17:31.373 回答