简体   繁体   English

格式化SQL输出(Pivot)

[英]Formatting SQL Output (Pivot)

This is running on SQL Server 2008. 这是在SQL Server 2008上运行。

Anyway, I have sales data, and I can write a query to get the output to look like this: 无论如何,我有销售数据,我可以编写一个查询来使输出看起来像这样:

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

etc. Currently, after running this data, I am rearranging the data in the code behind so that the final output looks like this: 目前,运行此数据后,我正在重新排列后面代码中的数据,以便最终输出如下所示:

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

The issues are: 问题是:

  1. The date (YYYY/MM) range is an input from the user. 日期(YYYY / MM)范围是来自用户的输入。
  2. If the user selects more outputs (like, say, address, and a ton of other possible fields relating to that customer), that information is duplicated in every line. 如果用户选择更多输出(例如,地址,以及与该客户相关的大量其他可能字段),则该信息在每一行中都是重复的。 When you're doing 10-15 items per line, over a period of 5+ years, for 50000+ users, this causes problems with running out of memory, and is also inefficient. 如果你在5年以上的时间内每行10-15个项目,对于50000多个用户来说,这会导致内存不足的问题,而且效率也很低。

I've considered pulling only the necessary data (the customer id -- how they're joined together, the period, and the sales figure), and then after the fact running a separate query to get the additional data. 我考虑过只提取必要的数据(客户ID - 它们如何连接在一起,期间和销售数字),然后运行单独的查询以获取其他数据。 This doesn't seem like it would be efficient though, but it's a possibility. 虽然它看起来并不高效,但这是一种可能性。

The other, which is what I'm thinking should be the best option, would be to rewrite my query to go ahead and do what my current code behind is doing, and pivot the data together, that way the customer data is never duplicated and I'm not moving a lot of unnecessary data around. 另一个,我认为应该是最好的选择,就是重写我的查询以继续执行我当前的代码所做的事情,并将数据转移到一起,这样客户数据永远不会重复,我没有移动很多不必要的数据。

To give a better example of what I'm working with, let's assume these tables: 为了更好地展示我正在使用的内容,让我们假设这些表:

Address 地址

id | HouseNum | Street | Unit | City | State

Customer 顾客

id | Name | 

Sales 销售

id | Period | Sales

So I would like to join these tables on the customer id, display all of the address data, assume the user inputs "2012/01 -- 2012/12", I can translate that into 2012/01, 2012/02 ... 2012/12 in my code behind to input into the query before it executes, so I have that available. 所以我想在客户ID上加入这些表格,显示所有地址数据,假设用户输入“2012/01 - 2012/12”,我可以将其翻译成2012 / 01,02012 / 02 ... 2012/12在我的代码背后,在执行之前输入查询,所以我有可用的。

What I want it to look like would be: 我希望它看起来像是:

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

(no sales data for that customer on 2012/02 -- if any of the data is blank I want it to be a blank string "", not a NULL) (2012/02年度没有该客户的销售数据 - 如果任何数据为空白我希望它是一个空白字符串“”,而不是NULL)

I realize I may not be explaining this the best way possible, so just let me know and I'll add more information. 我意识到我可能不会以最好的方式解释这个,所以请告诉我,我会添加更多信息。 Thank you! 谢谢!

edit: oh, one last thing. 编辑:哦,最后一件事。 Would it be possible to add a Min, Max, Avg, & Total columns to the end, which sum up all of the pivoted data? 是否可以在最后添加Min,Max,Avg和Total列,它们总结了所有的数据? It wouldn't be a big deal to do it on the code behind, but the more sql server can do for me the better, imo! 在后面的代码上做这件事并不是什么大不了的事,但是更多的sql server可以为我做得更好,imo!

edit: One more, the period is in the tables as "2013/01" etc, but I'd like to rename them to "Jan 2013" etc, if it's not too complicated? 编辑:还有一个,期间在表中作为“2013/01”等,但我想将它们重命名为“2013年1月”等,如果它不是太复杂?

You can implement the PIVOT function to transform the data from rows into columns. 您可以实现PIVOT函数将数据从行转换为列。 You can use the following to get the result: 您可以使用以下内容来获得结果:

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;

See SQL Fiddle with Demo . 请参阅SQL Fiddle with Demo

If you have a unknown number of period values that you want to transform into column, then you will have to use dynamic SQL to get the result: 如果要将未知数量的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)

See SQL Fiddle with Demo . 请参阅SQL Fiddle with Demo These give the result: 这些给出了结果:

| 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 |

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM