【问题标题】:SQL Query - Pivot loan summary by month dueSQL 查询 - 按到期月透视贷款摘要
【发布时间】:2016-02-10 22:52:33
【问题描述】:

这看起来很简单,但我正在努力解决这个问题。

我有一个贷款数据表,我想对每个月的到期付款进行透视和汇总。这类似于“静态池分析”,将每个贷款池作为行,将月份作为列。您可以使用此SQL Fiddle 查看示例数据。

我创建了一个90 second screencast 来更好地解释我需要的数据透视和汇总结果,如果有帮助的话。感谢您的帮助!

【问题讨论】:

    标签: mysql sql pivot


    【解决方案1】:

    如果它不需要是动态的,在 SUM 中使用 CASE WHEN 或 IF 语句应该在 MySQL 中充当 PIVOT:

    SELECT 
      PoolMonth, 
      SUM(OriginationAmt) AS Origination,
      SUM(IF(PmtDue = 201512, AmtPaid, 0)) AS `201512`,
      SUM(IF(PmtDue BETWEEN 201512 AND 201601, AmtPaid, 0)) AS `201601`,
      SUM(IF(PmtDue BETWEEN 201512 AND 201602, AmtPaid, 0)) AS `201602`
    FROM
      Loans
    GROUP BY
      PoolMonth;
    

    http://sqlfiddle.com/#!9/47701/16

    获取 OriginationAmt 的总数有点冗长,PoolMonth/PmtDue 的运行总数,并且只输出最新的运行总数,没有硬编码任何东西,但是我们开始 :-)

    SELECT
      t.PoolMonth,
      t.TtlOriginationAmt,
      t.PmtDue,
      t.RtAmtPaid
    FROM
      (
        SELECT 
          l.PoolMonth,
          l.OriginationAmt,
          orig.TtlOriginationAmt,
          l.PmtDue,
          /* Row_Number() equivalent for MySQL http://blog.sqlauthority.com/2014/03/09/mysql-reset-row-number-for-each-group-partition-by-row-number/ */
          /* Assign a Row Number for each Payment Due month for the individual Pool month in ascending order (ORDER BY clause important in this subquery) */
          @RowNumber := CASE WHEN @PoolMonth = l.PoolMonth AND @PmtDue = l.PmtDue THEN @RowNumber + 1 ELSE 1 END AS PoolPmtRowNumber,
          /* Use the total count of PmtDue month rows for each PoolMonth so we can limit our results to the final row */
          lr.PoolPmtLastRow,
          l.AmtPaid,
          /* Running total of Amount Paid for the individual Pool month in order of Payment Due month (ORDER BY clause important in this subquery) */
          @RtAmtPaid := CASE WHEN @PoolMonth = l.PoolMonth THEN @RtAmtPaid + l.AmtPaid ELSE l.AmtPaid END AS RtAmtPaid,
          /* Keep track of the Pool month we're totalling */
          @PoolMonth := l.PoolMonth,
          /* Keep track of the Payment Due month we're ordering */
          @PmtDue := l.PmtDue
        FROM
          Loans l
        JOIN
          /* Get the Total Origination Amount */
          (SELECT PoolMonth, SUM(OriginationAmt) AS TtlOriginationAmt FROM Loans GROUP BY PoolMonth) orig ON orig.PoolMonth = l.PoolMonth
        JOIN
          /* Get the total number of records by Pool/Payment due month so we can filter to the last row */
          (SELECT PoolMonth, PmtDue, COUNT(1) AS PoolPmtLastRow FROM Loans GROUP BY PoolMonth, PmtDue) AS lr ON lr.PoolMonth = l.PoolMonth AND lr.PmtDue = l.PmtDue
        CROSS JOIN
          /* Reset the variables we need for tracking */
          (SELECT @RtAmtPaid:=0,@PoolMonth:=0,@PmtDue:=0,@RowNumber:=0) var
        /* Order by Pool/Payment Due month */
        ORDER BY
          l.PoolMonth,
          l.PmtDue
      )t
    WHERE
      /* Filter to the last row */
      t.PoolPmtRowNumber = t.PoolPmtLastRow;
    

    http://sqlfiddle.com/#!9/47701/45

    从那里开始,应该很容易在 Excel 或其他任何地方转换您的结果。

    【讨论】:

    • 感谢您花时间回答。是的,这是可行的,但是,正如您所指出的,我的场景是动态的,并且 PmtDue 列中的月份不一样,这就是为什么需要在该列上进行数据透视的原因。
    • 我稍后会更新我的答案,但您实际上是在寻找这个:stackoverflow.com/questions/12004603/… 我通常避免在查询中使用动态 SQL,因为它很难阅读,我通常可以移动它一种更清晰的动态转向应用程序层(Excel、Tableau、Web 应用程序等)。
    • 我实际上可以使用 Excel 来透视数据,只要它可以以相同的方式进行汇总。 Excel 将允许我稍后在数据上添加过滤器。
    • 这应该会为您提供更容易工作的输出,而无需单独指定范围。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    • 2022-12-11
    • 1970-01-01
    相关资源
    最近更新 更多