【问题标题】:Selecting records for a yearly report (for the past 3 years)为年度报告选择记录(过去 3 年)
【发布时间】:2012-06-16 08:13:25
【问题描述】:

考虑以下 SQL 语句:

DECLARE @CustomerId INT = 48;
DECLARE @CurrentYear INT = DATEPART(YEAR, GETDATE());

SELECT
    YEAR(o.OrderDate) AS Year,
    0 AS Month,
    SUM(o.GrandTotal) AS GrandTotal
FROM [Order] o
WHERE
    o.CustomerId = @CustomerId AND
    o.OrderTypeId = 4 AND
    o.IsVoid = 0 AND
    YEAR(o.OrderDate) BETWEEN @CurrentYear - 2 AND @CurrentYear
GROUP BY
    YEAR(o.OrderDate)

正确地产生结果:

2012, 0, 89.00
2011, 0, 230.00
2010, 0, 450.0

但是,如果另一个客户仅在 2011 年下订单,我需要生成另外 2 行(尽管值为 0):

2011, 0, 230.00
2012, 0, 0
2010, 0, 0

我应该如何正确地做到这一点?请注意,将生成过去 3 年的报告。

第四次更新 我按照建议修改了代码:

DECLARE @CustomerId INT = 48;
DECLARE @CurrentYear INT = YEAR(GETDATE());

DECLARE @years TABLE (
    yr INT
);
INSERT INTO @years VALUES
    (@CurrentYear),
    (@CurrentYear - 1),
    (@CurrentYear - 2)

这会产生如下结果集(我已经检查过并确保是这种情况)。

2012
2011
2010

然后我加入表格(RIGHT JOIN)如下:

SELECT
    y.yr AS Year,
    0 AS Month,
    SUM(ISNULL(o.GrandTotal, 0)) AS GrandTotal
FROM [Order] o
RIGHT JOIN @years y ON y.yr = YEAR(o.OrderDate)
WHERE
    o.CustomerId = @CustomerId AND
    o.OrderTypeId = 4 AND
    o.IsVoid = 0
GROUP BY
    y.yr

但是,考虑到客户还没有下订单,所以,这需要产生 3 行的零值。但是,建议的这些解决方案都没有做到这一点。

最终更新 [已解决]: where 子句阻止这些行出现在最终结果集中。所以,正如 Darvin 所建议的,我只是用 AND 替换了 WHERE 子句,问题就消失了。

SELECT
    y.yr AS Year,
    0 AS Month,
    SUM(ISNULL(o.GrandTotal, 0)) AS GrandTotal
FROM [Order] o
RIGHT JOIN @years y ON y.yr = YEAR(o.OrderDate) AND
    o.CustomerId = @CustomerId AND
    o.OrderTypeId = 4 AND
    o.IsVoid = 0
GROUP BY
    y.yr

【问题讨论】:

  • 其他行没有显示的原因是通过将过滤器放在 where 子句上(与连接相反),在创建数据集后将排除行。
  • 好吧,我想通了。但是,我应该如何解决这个问题? (顺便说一下,我需要过滤这些行)。
  • 请参阅下面对我的版本的修改 - 如果不提​​供一些示例数据,我会看看哪里出错了

标签: sql-server sql-server-2008 tsql


【解决方案1】:

我在小提琴中编写了示例代码。 http://sqlfiddle.com/#!3/eddfe/9/0希望对您有所帮助。

这个想法是您创建一个包含所有年份的 UDF,然后对该表进行外部联接。

【讨论】:

    【解决方案2】:

    以下内容如何:

    DECLARE @CustomerId INT = 48; 
    DECLARE @CurrentYear INT = DATEPART(YEAR, GETDATE());  
    
    ;with years as 
    ( 
    SELECT YEAR(GETDATE()) as yr 
    UNION ALL SELECT YEAR(DATEADD(YY,-1,GETDATE())) 
    UNION ALL SELECT YEAR(DATEADD(YY,-2,GETDATE())) 
    ) 
    SELECT      
    years.yr 
    ,0 AS Month 
    ,SUM(ISNULL(o.GrandTotal,0)) AS GrandTotal  
    FROM years 
    LEFT OUTER JOIN Order o  
    ON YEAR(o.OrderDate) = years.yr 
    AND o.customerid = @customerid
    AND     o.OrderTypeId = 4  
    AND     o.IsVoid = 0  
    GROUP BY      
    years.yr 
    

    【讨论】:

    • @Mehdi - where 子句之前错误地排除了行 - 尝试修改版本
    • 谢谢,这个有效。但是,请您描述一下您编写的查询的第一版和第二版之间的区别是什么?我需要永远理解这一点:)
    • 不同之处在于过滤条件已移至联接(x = y、a = b 等上的左外部联接顺序)。以前的版本将日期加入到预定义的范围然后过滤,新版本只加入 customerID、ordertype 和 IsvOId 有效的情况。请参阅here 了解另一个示例
    猜你喜欢
    • 2011-09-30
    • 2015-09-16
    • 2013-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多