通过SQL向PIVOT组添加订单的问题

时间:2015-10-05 11:16:09

标签: sql-server group-by pivot-table

SQL Below工作gr8,但顺序,如何设置放置Jan,Feb,Mar命令。我知道我需要在序数月份执行此操作,但是当我按顺序添加时,我会收到错误 ' ORDER BY子句在视图,内联函数,派生表,子查询和公共中无效表表达式,除非还指定了TOP,OFFSET或FOR XML。'

结果如下:

enter image description here

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

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(year(TransactionDateTime))
            FROM Quotations
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

SET @query = 
    'SELECT *
    FROM (
        SELECT 
            left(datename(month,TransactionDateTime),3) as [month], year(TransactionDateTime) as [year],
            isnull(count(*),0) as Total 
        FROM quotations
        group by  left(datename(month,TransactionDateTime),3), year(TransactionDateTime)
    ) as s
    PIVOT
    (
        SUM(Total)
        FOR [year] IN (' + @cols + ')
    ) AS QuotationResults'



EXECUTE(@query)

1 个答案:

答案 0 :(得分:1)

如错误所示,除非订单有原因(TOPFOR XML等),否则您无法订购子查询。这样做的原因是,只是因为您已经订购了子查询,所以没有理由在外部查询中维护此顺序。 SQL Server基本上告诉您,ORDER BY毫无意义,因此无效。

解决方案是简单地将一个带月号的列添加到您的子查询s,然后您可以按顺序排序。您还需要明确说明您的选择列表,以确保此新列不会出现在其中:

DECLARE @cols AS NVARCHAR(MAX);
DECLARE @query AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(year(TransactionDateTime))
            FROM Quotations
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'');

SET @query = 
    'SELECT [month], ' + @Cols + '
    FROM (
        SELECT 
            left(datename(month,TransactionDateTime),3) as [month], 
            datepart(month,TransactionDateTime) as [monthNum], 
            year(TransactionDateTime) as [year],
            isnull(count(*),0) as Total 
        FROM quotations
        group by  left(datename(month,TransactionDateTime),3), datepart(month,TransactionDateTime), year(TransactionDateTime)
    ) as s
    PIVOT
    (
        SUM(Total)
        FOR [year] IN (' + @cols + ')
    ) AS QuotationResults
    ORDER BY QuotationResults.MonthNum;';

EXECUTE(@query);

<强>附录

ISNULL()不会捕获空值,因为在使用ISNULL()时它们不存在。 COUNT(*) 永远不会返回null,因此您的ISNULL()实际上是多余的。

如果你有一个非常简单的例子:

TransactionDateTime 
----------------------  
2015-01-01
2015-02-01
2015-02-01
2014-03-01

要向前跳一步,在您的支点后,您将最终得到:

Month   2014    2015
------------------------
Jan     NULL    1
Feb     NULL    2
Mar     1       NULL

所以你最终得到了NULL值,现在回到一步,如果你在汇总后看结果:

Month   MonthNum    Year    Total
-----------------------------------
Jan     1           2015    1
Feb     2           2015    2
Mar     3           2014    1

因此2014年1月或2月没有行,因此SUM(NULL)将产生NULL。我建议将所有聚合留给pivot功能。所以你的非动态查询看起来像:

SELECT  pvt.[Month], pvt.[2014], pvt.[2015]
FROM    (   SELECT  [Month] = LEFT(DATENAME(MONTH, TransactionDateTime), 3), 
                    [MonthNum] = DATEPART(MONTH, TransactionDateTime), 
                    [Year] = DATEPART(YEAR, TransactionDateTime),
                    Value = 1
            FROM    Quotations
        ) AS t
        PIVOT
        (
            COUNT(Value)
            FOR [year] IN ([2014], [2015])
        ) AS pvt
ORDER BY pvt.MonthNum;

并加入动态SQL:

DECLARE @cols AS NVARCHAR(MAX);
DECLARE @query AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(DATEPART(YEAR, TransactionDateTime))
            FROM Quotations
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'');

SET @query = 
    'SELECT pvt.[Month], ' + @cols + '
    FROM    (   SELECT  [Month] = LEFT(DATENAME(MONTH, TransactionDateTime), 3), 
                        [MonthNum] = DATEPART(MONTH, TransactionDateTime), 
                        [Year] = DATEPART(YEAR, TransactionDateTime),
                        Value = 1
                FROM    Quotations
            ) AS t
            PIVOT
            (
                COUNT(Value)
                FOR [year] IN (' + @cols + ')
            ) AS pvt
    ORDER BY pvt.MonthNum;
    (
        SUM(Total)
        FOR [year] IN (' + @cols + ')
    ) AS QuotationResults
    ORDER BY QuotationResults.MonthNum;';

EXECUTE sp_executesql @query;