条件运行总计SQL语句:对于交易记录集中的每个不同月份,获取列的最近十二个月总和

时间:2019-04-22 15:04:37

标签: sql sql-server tsql grouping

有一个事务处理表,其中包含2006年至2019年的日期数据,其中每个月(销售量)的记录数量为零到很多。要求是一条SQL语句,该语句每月获取我过去十二个月的销售总额以及包含值的不同月份的总数。

下面是到目前为止的SQL(有点混乱,因为日期保存在单独的表中,并且日期必须来自批处理)

WITH monthly_totals AS 
(SELECT  
    sum(t1.[Transaction_totals]) AS sum_of_sales, 
    CASE 
        WHEN t2.month_id % 100 < 10 AND t2.month_id/100 < 10 THEN CONCAT('200', t2.month_id % 100, '-0', t2.month_id / 100, '-01')
        WHEN t2.month_id % 100 < 10 AND t2.month_id/100 >= 10 THEN CONCAT('200', t2.month_id % 100, '-', t2.month_id / 100, '-01')
        WHEN t2.month_id % 100 >= 10 AND t2.month_id/100 < 10 THEN CONCAT('20', t2.month_id % 100, '-0',t2. month_id / 100, '-01')
        ELSE CONCAT('20', t2.month_id % 100, '-', t2.month_id / 100, '-01')
    END as date, 
    t2.month_id
FROM 
    TRANSACTION t1
INNER JOIN
    BATCH  t2 ON t1.batch_id = t2.batch_id
GROUP BY 
    CASE 
        WHEN t2.month_id % 100 < 10 AND t2.month_id/100 < 10 THEN CONCAT('200', t2.month_id % 100, '-0', t2.month_id / 100, '-01')
        WHEN t2.month_id % 100 < 10 AND t2.month_id/100 >= 10 THEN CONCAT('200', t2.month_id % 100, '-', t2.month_id / 100, '-01')
        WHEN t2.month_id % 100 >= 10 AND t2.month_id/100 < 10 THEN CONCAT('20', t2.month_id % 100, '-0',t2. month_id / 100, '-01')
        ELSE CONCAT('20', t2.month_id % 100, '-', t2.month_id / 100, '-01')
    END, 
    t2.month_id
) 
SELECT 
    sum(sum_of_sales) AS sum_of_sales, 
    count(distinct month_id) as month_count, 
    date
FROM 
    monthly_totals
WHERE 
date IN (select distinct month_id
        from 
            vw_dimDate as d
        where 
            date >= (
                select 
                    distinct(date)
                from 
                    dimDate
                where 
                    month_id = month_id
                    and dayNumber = 1) - 365
        and 
            date <= (
                select 
                    distinct(date)
                from 
                    dimDate
                where 
                    month_id = month_id
                    and dayNumber = 1
            )
        )
GROUP BY 
    date

但这会引发以下错误: 子查询返回的值超过1。当子查询遵循=,!=,<,<=,>,> =或将子查询用作表达式时,不允许这样做。

对于一个跨越13年的表,最终产品应该是这样的:

2006-01-01:$ 2,382,823 [2005年1月1日至2006年1月1日的销售总额],1 [交易的月份数不同]

2006-02-01 $ 4,382,823 [2005年2月1日至2006年2月1日的销售总额],2 [交易月数不同]

2006-03-01 $ 4,382,823 [从2005-03-01开始的总销售额-2006-03-01],3 [交易月份数不同]

... 2010-01-01:23,323,204美元[2009年1月1日至2010年1月1日的销售总和],12个[交易月份数不同]

2011-01-01:12,938,823美元(2009年2月1日至2010年2月1日的销售总额),12个[交易月数不同]

等... 表格中的每个月

4 个答案:

答案 0 :(得分:1)

只是想知道是否有一个驱动它的日期表并将其连接到交易表是否更好,那么您应该能够使用前12个月的总和分区,并计算交易<> 0 ...如果...加入下面的表格。

此网站上的其他人可能会肯定知道这是否可行。

with years as (
     select * from 
     (values(2006),(2007),(2008),(2009),(2010),(2011),(2012),(2013),(2014),(2015),(2016),(2017),(2018),(2019)
     ) as t (Year_id))
,months as (
     select * from 
     (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
     ) as t (month_id))
select Year_id,month_id,0 as [Transaction_totals]
from years
cross join months
order by 1,2

答案 1 :(得分:0)

根据Roger Clerkwell的建议,我将首先使用With With Block(CTE)创建一个Dates表,然后在其余的查询中使用。这样一来,您便可以根据从日期表中拉回的日期来查询数据。

由于我正在使用Oracle数据库,因此我的解决方案说明了如何创建一个日期表,该表为输入到查询中的日期范围生成一个月开始日期的列表。它还可以产生月份的结束日期,但是,我意识到,对于这个问题,不需要月份的结束日期。我在其中使用了无数报告。通过一些小的调整,如果您需要每天查询结果,并且完全了解CONNECT BY LEVEL之后,此代码也可以产生不同的结果。

SELECT TRUNC(ADD_MONTHS('01-JUL-18', LEVEL-1), 'MM') START_DATE,
       LAST_DAY(ADD_MONTHS('01-JUL-18', LEVEL-1)) END_DATE
FROM DUAL CONNECT BY LEVEL <= CEIL(MONTHS_BETWEEN('30-JUN-19', '01-JUL-18'))
;

该代码将产生类似于以下屏幕截图的结果。 enter image description here

SQL Server不需要利用dual表。如果您对双重表格有疑问,请参见THIS Stackoverflow问题。

答案 2 :(得分:0)

WITH CTE AS (
   SELECT 2006 AS Year
  UNION ALL
  SELECT Year + 1 FROM CTE  WHERE Year < 2019
 ),CTE2 AS (
 SELECT 1 AS Month
 UNION ALL
 SELECT Month + 1 FROM CTE2  WHERE Month < 12
 )
 select dateadd(mm,datediff(mm,-1,dateadd(year,-1,convert(varchar,year)+'- '+convert(varchar,Month)+'-'+'1')),-1)start_Date,
dateadd(mm,datediff(mm,-1,convert(varchar,year)+'-'+convert(varchar,Month)+'-  '+'1'),-1)End_Date
  from CTE 
cross join CTE2
order by 1
OPTION (MAXRECURSION 0)

答案 3 :(得分:0)

谢谢Roger,Stuphan和Stark博士的建议。昨天,我对交叉连接并不熟悉,所以继续走另一条路,找到了替代解决方案。但是,在查看日期表后,您已经看到了有关创建方法的示例,如果我今天要重新执行此操作,则可以采用这种方法。作为记录,这就是我如何解决的:(基本上使用两次相同的每月总计数据集,这允许第一个数据集提供日期,而第二个数据集提供滚动的年度平均值) / p>

每月(总计)AS (选择
    sum(t1。[Transaction_totals])AS sum_of_sales,     t5.date,     product_id,     t1.store_id

从     交易t1

内部联接     批处理t2开启t1.batch_id = t2.batch_id

内部联接     vw_dimDate t5 ON t4.month_id = t5.month_id AND t4.year = t5.year AND t5.dayNumber = 1

组别     t5.date,     product_id,     t1.store_id ),年总计为( 选择     t1.date,     t1.store_id,     t1.product_id,     sum(t2.sum_of_sales)AS sum_of_sales,     计数(与t2.date截然不同)为month_count

从     每月总计t1

内部联接     t2.date> DATEADD(年,-1,CONVERT(DATE,t1.date))AND t2.date <= CONVERT(DATE,t1.date)AND t1.store_id = t2.store_id AND t1.product_id = t2.product_id

组别     t1.date,     t1.store_id,     t1.product_id

) 选择     日期,     store_id,     product_id,     sum_of_sales / month_count * 12作为sum_of_sales,     month_count

订购     t1.date,     store_id,     product_id