2

我正在尝试为多个可变销售中心提取每个月的销售业务数量。使用以下 TSQL ...

;WITH Months(m) AS
(
    SELECT 1 m
    UNION ALL 
    SELECT m+1 FROM Months WHERE m < 12
)
SELECT  t.Center,m Month, t.Sales FROM Months
CROSS APPLY 
(
    SELECT C.Center, COUNT(1) Sales FROM Operations C
    LEFT JOIN Centers A ON A.Code=C.Center
    WHERE Date BETWEEN '01/'+ CONVERT(VARCHAR(2),Months.m) + '/2013' AND DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,'01/'+ CONVERT(VARCHAR(2),Months.m) + '/2013')+1,0))
    GROUP BY C.Center
) t

所以我得到以下输出:

Center   Month   Sales
-----------------------
A        1       20
B        1       30
A        2       25
B        2       30
....

我想结束的是:

Center   1    2    ...
----------------------
A        20   25   ...
B        30   30   ...

我正在用 xmlpath 研究枢轴,但它太复杂了,我无法让它工作。有人有解决方案吗?

4

3 回答 3

1

也许我在你的问题上遗漏了一些东西,但由于一年只有 12 个月,所以没有理由使用动态 SQL,因为你只会有 12 列。

这可以使用以下查询轻松完成:

select center, 
  [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12]
from
(
  select o.center, month(date) month
  from operations o
  inner join centers c
    on o.center = c.code
  where c.date >= '2013-01-01'
    and c.date <= '2013-12-31'
) d
pivot
(
  count(month)
  for month in ([1], [2], [3], [4], [5], [6], [7], [8], [9], 
                [10], [11], [12])
) piv

请参阅SQL Fiddle with Demo

如果要动态执行此操作,则可以使用以下命令:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @startdate datetime,
    @enddate datetime

set @startdate = '2013-01-01'
set @enddate = '2013-12-31'

;WITH Months(m) AS
(
    SELECT 1 m
    UNION ALL 
    SELECT m+1 FROM Months WHERE m < 12
)
select @cols = STUFF((SELECT ',' + QUOTENAME(m) 
                    from Months
                    group by m
                    order by m
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT center, ' + @cols + ' 
            from 
            (
              select o.center, month(date) month
              from operations o
              inner join centers c
                on o.center = c.code
              where c.date >= '''+convert(varchar(10), @startdate, 120)+'''
                and c.date <= '''+convert(varchar(10), @enddate, 120)+'''
            ) x
            pivot 
            (
                count(month)
                for month in (' + @cols + ')
            ) p '


execute sp_executesql @query;

请参阅带有演示的 SQL Fiddle

于 2013-08-02T11:53:11.093 回答
0

我终于实现了 BlueFeet 的第一个建议,稍作改动:

;WITH Months(m) AS
(
    SELECT 1 m
    UNION ALL 
    SELECT m+1 FROM Months WHERE m < 12
)
SELECT * FROM Months
CROSS APPLY 
(
    SELECT C.Center, COUNT(1) Sales FROM Operations C
    LEFT JOIN Centers A ON A.Code=C.Center
    WHERE Date BETWEEN '01/'+ CONVERT(VARCHAR(2),Months.m) + '/2013' AND DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,'01/'+ CONVERT(VARCHAR(2),Months.m) + '/2013')+1,0))
    GROUP BY C.Center
) t
pivot
(
    max(Sales)
    for m in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
) as PIV

我正在寻找的不是在数据透视语句上写月份数字,所以我只能返回一个季度,例如。但这使得工作成为必需。谢谢。

于 2013-08-07T08:40:11.210 回答
0

不要这样做。为什么要与 Sql Server 做一些不该做的事情?

让您的查询垂直返回数据,就像现在一样。

在应用程序级别转置它。
编写、调试、维护和处理无疑会弹出的特殊业务规则会容易得多。

此外,它将更容易将数据粘贴到 Excel 中以进行故障排除和透视。

于 2013-08-03T19:26:29.797 回答