【问题标题】:How to make a SQL query for last transaction of every account?如何对每个账户的最后一笔交易进行 SQL 查询?
【发布时间】:2020-04-08 01:57:19
【问题描述】:

假设我有一个表“事务”,其中包含列“acct_id”、“trans_date”和“trans_type”,我想过滤这个表,以便我只有每个帐户的最后一笔交易。显然我可以做类似的事情

SELECT acct_id, max(trans_date) as trans_date  
FROM transactions GROUP BY acct_id;

但后来我失去了我的 trans_type。然后,我可以使用我的日期列表和帐户 ID 进行第二次 SQL 调用,并取回我的 trans_type,但这感觉非常麻烦,因为这意味着要么将数据来回发送到 sql 服务器,要么意味着创建一个临时表。

有没有办法通过单个查询来做到这一点,希望是一种适用于 mysql、postgres、sql-server 和 oracle 的通用方法。

【问题讨论】:

    标签: sql greatest-n-per-group


    【解决方案1】:

    这是greatest-n-per-group 查询的示例。这个问题每周在 StackOverflow 上出现好几次。除了其他人给出的子查询解决方案之外,这是我的首选解决方案,它不使用子查询,GROUP BY 或 CTE:

    SELECT t1.*
    FROM transactions t1
    LEFT OUTER JOIN transactions t2
      ON (t1.acct_id = t2.acct_id AND t1.trans_date < t2.trans_date)
    WHERE t2.acct_id IS NULL;
    

    换句话说,返回一行,使得不存在具有相同acct_id 和更大trans_date 的其他行。

    此解决方案假定trans_date 对于给定帐户是唯一的,否则可能会发生绑定并且查询将返回所有绑定的行。但这也适用于其他人给出的所有解决方案。

    我更喜欢这个解决方案,因为我经常使用 MySQL,它不能很好地优化 GROUP BY。因此,这种外连接解决方​​案通常被证明具有更好的性能。

    【讨论】:

      【解决方案2】:

      这适用于 SQL Server...

      SELECT acct_id, trans_date, trans_type
      FROM transactions a
      WHERE trans_date = (
         SELECT MAX( trans_date )
         FROM transactions b
         WHERE a.acct_id = b.acct_id
      )
      

      【讨论】:

      • 这是我的最爱。您还可以将 where 子句设为 NOT EXISTS (SELECT NULL FROM transaction z WHERE a.acct_id = z.acct_id AND z.trans_date &gt; a.trans_date)
      【解决方案3】:

      试试这个

      WITH 
      LastTransaction AS
      (
          SELECT acct_id, max(trans_date) as trans_date  
          FROM transactions 
          GROUP BY acct_id
      ),
      AllTransactions AS
      (
          SELECT acct_id, trans_date, trans_type
          FROM transactions 
      )
      SELECT *
      FROM AllTransactions
      INNER JOIN LastTransaction
          ON AllTransactions.acct_id = LastTransaction.acct_id
          AND AllTransactions.trans_date  = LastTransaction.trans_date
      

      【讨论】:

      • 不幸的是,仍在广泛使用的 MySQL 5.7 不支持 WITH 语法。
      【解决方案4】:
      select t.acct_id, t.trans_type, tm.trans_date
      from transactions t
      inner join (
          SELECT acct_id, max(trans_date) as trans_date  
          FROM transactions 
          GROUP BY acct_id;
      ) tm on t.acct_id = tm.acct_id and t.trans_date = tm.trans_date
      

      【讨论】:

      • 这就是我修复的,在 ON 子句中省略了 trans_date。
      猜你喜欢
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-29
      • 1970-01-01
      • 1970-01-01
      • 2011-03-20
      • 2022-07-08
      相关资源
      最近更新 更多