在select语句中使用IF,逐月对值进行分组

时间:2016-05-03 15:05:25

标签: mysql datetime group-by aggregate-functions pivot-table

我正在尝试运行一个报表,该报表将按费用表格逐月分组费用帐户的总计,每个行包含以下列:

expense_acc
debit
credit
post_date

报告的所需输出采用以下列格式: EXP ACC - JAN - FEB - MAR

这是我的SQL选择查询:

SELECT expense_acc,
if(MONTH(post_date)=1,SUM(expenses.debit-expenses.credit),0) AS 'JAN',
if(MONTH(post_date)=2,SUM(debit-credit),0) AS 'FEB',
if(MONTH(post_date)=3,SUM(debit-credit),0) AS 'MAR'
FROM expenses
WHERE YEAR(expenses.entered)='2016'
GROUP BY expenses.expense_acc

结果不按预期按月对费用值进行分组。无论交易日期如何,我都会在第一行看到分组。

3 个答案:

答案 0 :(得分:1)

根据您的要求,您有两个部分。

  1. 表格内容的逐月汇总
  2. 一个数据透视表呈现,您可以在其中按月将行旋转到列中。
  3. 此外,如果SUM(expenses.debit-expenses.credit)debit列包含credit值,则NULL不具备弹性。

    此外,YEAR(date)会使date上的任何索引失败。

    如果您明智,您将分两步处理这些要求。首先,对结果进行故障排除会更容易。另一方面,下一个出席的人将更好地了解您的项目。

    逐月汇总:

           SELECT expense_acc, LAST_DAY(post_date) month_ending,
                  SUM(expenses.debit) - SUM(expenses.credit) as net_expenses
             FROM expenses
            WHERE post_date >= '2016-01-01'
              AND post_date < '20016-12-31' + INTERVAL 1 DAY
            GROUP BY expense_acc, LAST_DAY(post_date)
            ORDER BY expense_acc, LAST_DAY(post_date)
    

    这会为每个帐户和日期提供一行。该行将显示帐户,月末日期和净费用。 (我不明白你的例子中expenses.entered。最好在你用来制作聚合的同一天过滤。)你的审计员会理解这种逻辑分离。

    接下来,您可以将其用作子查询,以显示枢轴。

    这很简单:

     SELECT expense_acc,
            SUM(IF(MONTH(month_ending)=1,net_expenses,0)) as jan,
            SUM(IF(MONTH(month_ending)=2,net_expenses,0)) as feb,
            SUM(IF(MONTH(month_ending)=3,net_expenses,0)) as mar, 
            ...
       FROM (
           SELECT expense_acc, LAST_DAY(post_date) month_ending,
                  SUM(expenses.debit) - SUM(expenses.credit) as net_expenses
             FROM expenses
            WHERE post_date >= '2016-01-01'
              AND post_date < '20016-12-31' + INTERVAL 1 DAY
            ) z
      GROUP BY expense_acc
      ORDER BY expense_acc
    

    但是,您可能希望在客户端程序中进行透视。编写和维护MySQL数据透视代码非常困难。

答案 1 :(得分:0)

SELECT 
SUM(JAN) AS JAN,
SUM(FEB) AS FEB
SUM(MAR) AS MAR
FROM
(

SELECT expense_acc,
if(MONTH(post_date)=1,SUM(expenses.debit-expenses.credit),0) AS 'JAN',
if(MONTH(post_date)=2,SUM(debit-credit),0) AS 'FEB',
if(MONTH(post_date)=3,SUM(debit-credit),0) AS 'MAR'
FROM expenses
WHERE YEAR(expenses.entered)='2016'
GROUP BY expenses.expense_acc
)TMP
GROUP BY expense_acc

答案 2 :(得分:0)

在我看来,最佳方式是:

SELECT expense_acc, MONTH(post_date) month_num, SUM(debit-credit) as total
FROM expenses
WHERE YEAR(expenses.entered) = '2016'
GROUP BY expenses.expense_account, MONTH(post_date)

这会给你类似的东西

|expense account |   mont_num   | total |
-----------------------------------------
|    2345        |       1      |   50  |
-----------------------------------------
|    2345        |       2      |   30  |
-----------------------------------------
|    2346        |       1      |   45  |

...

因为如果你每月做一个if语句,你会得到12个ifs。 管理控制器中的行格式会更好。

希望它会对你有所帮助。