【问题标题】:sql query to dynamically add fiscal month using pivot使用数据透视动态添加会计月份的 sql 查询
【发布时间】:2013-01-15 17:36:34
【问题描述】:
ALTER PROCEDURE [dbo].[_sp_GetDMActivityTrackerReport]
@CoachId VARCHAR(7),
@Month INT,
@FiscalYear INT
AS 
BEGIN    

INSERT @FiscalMonth (ID,Month,NbHolidays,MonthDate,TotalDays)
EXECUTE dbo._sp_GetFiscalMonths @Month, @FiscalYear

SELECT PreparationID,CoachId,UserID, MemberID,
[Rep Name], isnull(April,0) April, isnull(May,0) May, isnull(June,0)June,
isnull(July,0) July, isnull(August,0) August, isnull(September,0) September, 
isnull(October,0) October, isnull(November,0) November,
isnull(December,0) December, isnull(January,0) January, isnull(February,0) February,
isnull(March,0) March,isnull((isnull(November,0) + isnull(December,0) + 
isnull(January,0) + isnull(February,0) + isnull(March,0) + isnull(April,0) +
isnull(May,0) + isnull(June,0) + isnull(July,0) + isnull(August,0) +
isnull(September,0) + isnull(October,0)),0) as [Total Field TIME] 

FROM
(
SELECT up.PreparationID,tt.UserId [CoachId],up.UserID, utm.MemberID, 
(ui.FirstName + ' ' + ui.LastName) AS [Rep Name],DateName(Month,nft.MonthPeriodStart) [Month], sum(nft.Quantity) [Days]

FROM TransferedTime tt
INNER JOIN UPreparation up ON tt.PreparationID = up.PreparationID 
RIGHT JOIN UTeamMembers utm ON tt.UserId = utm.CoachID AND utm.MemberID = up.UserID
INNER JOIN UserInfo ui ON utm.MemberID = ui.UserID
LEFT JOIN NonFieldTime nft ON nft.UserId = tt.UserId 
AND tt.MonthPeriodFrom = nft.MonthPeriodStart
AND datename(Month,nft.MonthPeriodStart) + '-'+ substring(datename(Year,nft.MonthPeriodStart),3,2) IN 
(SELECT Month +'-' +substring(datename(Year,MonthDate),3,2) [Months] FROM @FiscalMonth)
WHERE utm.MemberID IN (SELECT MemberID FROM UTeamMembers WHERE CoachID = @CoachId)
GROUP BY up.PreparationID,tt.UserId,up.UserID, utm.MemberID,
(ui.FirstName + ' ' + ui.LastName),DateName(Month,nft.MonthPeriodStart)) src 
pivot 
(
sum(Days)
for Month in (April, May, June, July, August, September, October,November, December, January, February, March)
)
piv 

@Fiscalmonth returns:
Id, Month, NbHolidays, MonthDate
1   April     1 4/1/2012
2   May   2 5/1/2012 
3   June      3 6/1/2012
4   July      4 7/1/2012
5   August    5 8/1/2012
6   September 6 9/1/2012
7   October   7 10/1/2012
8   November  8 11/1/2012
9   December  9 12/1/2012
10  January   10    1/1/2013
11  February  11    2/1/2013
12  March     12    3/1/2013

我有一个根据会计年度生成报告的存储过程。 这里的财政年度和财政月份来自数据库现在我在动态生成此报告时遇到了问题,正如你所看到的,我已经修复了月份年份,这不是一个好习惯,如果我更改了财政月份,我希望它以某种方式数据库然后我的报告相应地反映。

【问题讨论】:

  • 所以您想基本上完全按照您在此处所做的操作,而无需在数据透视表逻辑中对月份进行硬编码?
  • 答案是可以接受的,如果它解决了我的问题.. :)
  • @Love2Learn 您应该将您的别名更改为 RepLove
  • @Love2Learn 这完全是错误的做法。如果您想获得代表,请写出好的答案,注意确保您的态度友好,并且在您知道之前,您将获得所需的一切。作为一个混蛋“我只会在你注意答案的情况下提供帮助”绝对是错误的处理方式。作为一个例子,我会指出stackoverflow.com/questions/14261062/…,我的答案比其他大多数人都晚,而且我得到了所有人的最多支持和接受。
  • @dIvYaNsHsInGh 使用您的表格和一些示例数据创建一个sql fiddle 可能对获得正确的语法很有帮助。

标签: sql sql-server-2008 pivot


【解决方案1】:

您需要使用动态 SQL 来执行此操作。 粗略的代码将与此类似:

ALTER PROCEDURE [dbo].[_sp_GetDMActivityTrackerReport]
    @CoachId VARCHAR(7),
    @Month INT,
    @FiscalYear INT
AS 
BEGIN    

INSERT @FiscalMonth (ID,Month,NbHolidays,MonthDate,TotalDays)
EXECUTE dbo._sp_GetFiscalMonths @Month, @FiscalYear

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

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(DateName(Month,nft.MonthPeriodStart)) 
                    from NonFieldTime nft
                    where datename(Month,nft.MonthPeriodStart) + '-'+ substring(datename(Year,nft.MonthPeriodStart),3,2) 
                        IN (SELECT Month +'-' +substring(datename(Year,MonthDate),3,2) [Months] 
                            FROM +@FiscalMonth)
            FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')

select @colsNull = STUFF((SELECT distinct ', IsNull(' + QUOTENAME(DateName(Month,nft.MonthPeriodStart))+', 0) as '+DateName(Month,nft.MonthPeriodStart)
                    from NonFieldTime nft
                    where datename(Month,nft.MonthPeriodStart) + '-'+ substring(datename(Year,nft.MonthPeriodStart),3,2) 
                        IN (SELECT Month +'-' +substring(datename(Year,MonthDate),3,2) [Months] 
                            FROM +@FiscalMonth)
            FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')

select @colsSum = STUFF((SELECT distinct '+ IsNull(' + QUOTENAME(DateName(Month,nft.MonthPeriodStart))+', 0)'
                    from NonFieldTime nft
                    where datename(Month,nft.MonthPeriodStart) + '-'+ substring(datename(Year,nft.MonthPeriodStart),3,2) 
                        IN (SELECT Month +'-' +substring(datename(Year,MonthDate),3,2) [Months] 
                            FROM +@FiscalMonth)
            FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')+' as [Total Field TIME] '

set @query = 'SELECT PreparationID,CoachId,UserID, MemberID,
                    [Rep Name], ' + @colsNull + ', '+ @colsSum+' 
             from 
             (
                SELECT up.PreparationID,
                    tt.UserId [CoachId],
                    up.UserID, utm.MemberID, 
                    (ui.FirstName + '' '' + ui.LastName) AS [Rep Name],
                    DateName(Month,nft.MonthPeriodStart) [Month], 
                    sum(nft.Quantity) [Days]
                FROM TransferedTime tt
                INNER JOIN UPreparation up 
                    ON tt.PreparationID = up.PreparationID 
                RIGHT JOIN UTeamMembers utm 
                    ON tt.UserId = utm.CoachID AND utm.MemberID = up.UserID
                INNER JOIN UserInfo ui 
                    ON utm.MemberID = ui.UserID
                LEFT JOIN NonFieldTime nft 
                    ON nft.UserId = tt.UserId 
                    AND tt.MonthPeriodFrom = nft.MonthPeriodStart
                    AND datename(Month,nft.MonthPeriodStart) + ''-''+ substring(datename(Year,nft.MonthPeriodStart),3,2) IN 
                        (SELECT Month +''-'' +substring(datename(Year,MonthDate),3,2) [Months] 
                         FROM +@FiscalMonth)
                WHERE utm.MemberID IN (SELECT MemberID 
                                        FROM UTeamMembers 
                                        WHERE CoachID = '+@CoachId+')
                GROUP BY up.PreparationID,tt.UserId,up.UserID, utm.MemberID,
                (ui.FirstName + '' '' + ui.LastName),DateName(Month,nft.MonthPeriodStart)
            ) x
            pivot 
            (
                sum(Days)
                for Month in (' + @cols + ')
            ) p '

execute(@query)

我的建议不是使用临时表@FiscalMonth,而是为此创建一个永久的表。使用动态 sql 时,查询 perm 表而不是 temp 表会简单得多。临时表可能超出动态查询的范围。

【讨论】:

  • 它超出了范围,但是,解决这个问题,这就是你想要的。
  • 感谢@bluefeet 它几乎可以正常工作我唯一想知道的是现在我在“NonFieldTime”表中只有两个月的数据,即 12 月和 1 月,所以它显示了他们的结果,但我必须展示其余的也是几个月。
  • @dIvYaNsHsInGh 因为您正在动态提取值,所以透视列将基于表中的内容。如果您想确保包含每个月或使用查询的硬编码版本,则需要加入一年中所有月份的列表。
  • @dIvYaNsHsInGh 如果您需要所有月份,那您为什么说固定月份是不好的做法,这正是您所需要的。你不需要动态 sql
  • @lamak 实际上现在我的财政月从“四月”开始,未来可能是“六月”,对于其他客户来说,这就是我希望它转换为动态查询的原因。
【解决方案2】:

Oracle 中有 PIVOT XML 选项,可让您避免硬编码。我不确定 SQL Server 中是否有这样的选项。你可以这样写 - 也可以是 Oracle 查询:

SELECT count(decode(state,'FL',custid)) "FL"
     , count(decode(state,'NY',custid)) "NY"
     , count(decode(state,'CA',custid)) "CA"
FROM scott.customer
GROUP BY state
/

将状态替换为月份等... 输出:

FL  NY  CA
--- --- ---
0   2   0
5   0   8

Oracle 示例:

http://www.oracle-base.com/articles/11g/pivot-and-unpivot-operators-11gr1.php

SELECT * FROM   
(
 SELECT product_code, quantity
   FROM   pivot_test
)
PIVOT XML
(
 SUM(quantity) AS sum_quantity 
  FOR (product_code) IN (SELECT DISTINCT product_code 
                        FROM   pivot_test
                       WHERE  id < 10)
)
/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    • 2016-10-28
    相关资源
    最近更新 更多