SQL - 如何按日期将数据拆分到不同的每月“盆”中?

时间:2017-09-06 16:34:14

标签: sql

sql新手,无法解决以下问题,但对于经验丰富的用户来说可能很简单。我有一张优秀的钱币表,我需要将它分成每月一桶;该表格包含以下列:

Name, amount_due, date_due.

我需要将信息除以' date_due'分为5个不同的月盆,当月,上个月,2个月,3个月,> 3个月大。

3 个答案:

答案 0 :(得分:2)

我假设您在每月执行SUM的摘要数据之后,而不是按月显示所有行。

name   , amount_due, date_due
Alice  ,        100, 2017-09-10
Bob    ,        500, 2017-07-03
Charlie,        300, 2017-07-02
Dan    ,        150, 2017-04-01
Eve    ,        200, 2017-01-01
Faith  ,         50, 2017-09-13

此查询将date_due值转换为“月”值(同时仍保留datedatetime类型信息),然后按月汇总:

输出:

sum_amount_due, month_due
           150, 2017-09-01
           800, 2017-07-01
           150, 2017-04-01
           200, 2017-01-01

SQL:

SELECT
    SUM( amount_due ) AS sum_amount_due,
    DATEADD( month, DATEDIFF( month, 0, date_due ), 0 ) AS month_due
FROM
    your_table
GROUP BY
    DATEADD( month, DATEDIFF( month, 0, date_due ), 0 )
ORDER BY
    month_due

此查询不会特别处理3个月以上的日期,因此我们需要更改month_due表达式,以便在3个月以前的日期返回'2001-01-01'

输出:

sum_amount_due, month_due
           150, 2017-09-01
           800, 2017-07-01
           350, 2000-01-01

SQL:

SELECT
    SUM( amount_due ) AS sum_amount_due,
    CASE
        WHEN date_due < DATEADD( month, GETDATE(), -3 ) THEN '2000-01-01'
        ELSE DATEADD( month, DATEDIFF( month, 0, date_due ), 0 )
    END AS month_due
FROM
    your_table
GROUP BY
    CASE
        WHEN date_due < DATEADD( month, GETDATE(), -3 ) THEN '2000-01-01'
        ELSE DATEADD( month, DATEDIFF( month, 0, date_due ), 0 )
    END
ORDER BY
    month_due

由于SQL的工作原理,您需要在SELECTGROUP BY子句中重复获取月份表达式。

通过使用子查询识别超过3个月的记录,可以在语法上略微简化:

SELECT
    SUM( amount_due ) AS sum_amount_due,
    CASE
        WHEN month_due_3_months THEN '2000-01-01'
        ELSE month_due
    END AS month_due
FROM
(
    SELECT
        amount_due,
        DATEADD( month, DATEDIFF( month, 0, date_due ), 0 ) AS month_due,
        CASE
            WHEN DATEADD( month, DATEDIFF( month, 0, date_due ), 0 ) < DATEADD( month, GETDATE(), -3 ) THEN 1
            ELSE 0
        END AS month_due_3_months
    FROM
        your_table
) AS all_months
GROUP BY
    CASE
        WHEN month_due_3_months THEN '2000-01-01'
        ELSE month_due
    END AS month_due
ORDER BY
    month_due

语法复杂性是由于SQL语言中固有的一些约束:

  • SELECT子句(“投影”)在 FROM AND GROUP BY子句后进行评估,因此您无法引用别名表达式在GROUP BY中:您必须重复它们或在子查询中指定它们。
  • SQL没有Get month as date value功能,令人惊讶的是,您必须使用DATEADD( month, DATEDIFF( month, 0, @dateValue ), 0 )
    • 请勿使用GETMONTHDATEPART,因为它只返回月份组件而忽略年份值,因此会错误地对来自同一月份的不同年份的行进行分组。
  • SQL中没有三元运算符,只有更详细的CASE WHEN x THEN y ELSE z END构造(尽管有COALESCENULLIFISNULL,但这些是特殊情况)

答案 1 :(得分:1)

我假设所有期间都是累积的,否则你需要修改每个条件。如果这符合预期或需要修改,请告诉我。

select name 
    ,sum( case when datediff(day,getdate(),date_due)<day(date_due) then amount_due end) 'current month'
    ,sum( case when datediff(month,getdate(),date_due)<=1 then amount_due end) 'last month'
    ,sum( case when datediff(month,getdate(),date_due)<=2 then amount_due end) 'last two month'
    ,sum( case when datediff(month,getdate(),date_due)<=3 then amount_due end) 'last three month'
    ,sum( case when datediff(month,getdate(),date_due)>3 then amount_due end) 'more than three month'
from monies
group by name

答案 2 :(得分:0)

用例来确定到期月份之间的due_date

SELECT name,
       amount_due,
       due_date,
       CASE WHEN CAST(due_date AS DATETIME) BETWEEN DATEADD(mm, -1, GETDATE()) AND DATEADD(mm, 0, GETDATE())
            THEN 'this month'
            WHEN CAST(due_date AS DATETIME) BETWEEN DATEADD(mm, -2, GETDATE()) AND DATEADD(mm, -1, GETDATE())
            THEN 'last month'
            WHEN CAST(due_date AS DATETIME) BETWEEN DATEADD(mm, -3, GETDATE()) AND DATEADD(mm, -2, GETDATE())
            THEN '2 months old'
            WHEN CAST(due_date AS DATETIME) BETWEEN DATEADD(mm, -4, GETDATE()) AND DATEADD(mm, -3, GETDATE())
            THEN '3 months old'
            WHEN CAST(due_date AS DATETIME) < DATEADD(mm, -4, GETDATE())
            THEN '> 3 months old'
        END month_of_due