【问题标题】:Find the average over the n last purchases, for every user in the table using SQL使用 SQL 查找表中每个用户最近 n 次购买的平均值
【发布时间】:2021-10-07 02:16:36
【问题描述】:

我有一个带有两个表的 SQLite 数据库:

用户

userID field1 field2 field3 field4
1
2
3

购买

purchaseID userID price timestamp
1 2 70 5166323
2 1 30 6543654
3 1 100 5456434
4 2 30 5846541
5 2 40 9635322
6 1 50 2541541

我想写一个返回表的 SQL 查询

userID field1 field2 field3 field4 avgPrice
1
2
3

其中 avgPrice 对应于用户 n 最后一次购买的平均价格。

我设法编写了以下查询,它计算每个用户购买的平均价格:

SELECT
    users.userID,
    users.field1,
    users.field2,
    users.field3,
    users.field4,
    avg(purchases.price)
FROM purchases
JOIN users on users.userID = purchases.userID
GROUP BY purchases.userID

但我想不出任何有效的方法来计算过去 n 次购买的平均值。 (我能找到的唯一方法涉及内部查询并且效率非常低)。

感谢您帮助解决此问题。 (仅供参考,这里的表格是我实际使用的表格的简化版本)。

【问题讨论】:

  • field1、field2、...的列是什么?他们和你的要求有关系吗?
  • 为什么您没有提供任何字段列的示例数据,您甚至需要它们来说明您的问题吗?可能只需要您的 Purchases 表。请提供实际所需的结果,请参阅Minimal, Reproducible Example

标签: sql database sqlite average window-functions


【解决方案1】:

您可以为此使用相关子查询:

SELECT u.*,
       (SELECT AVG(p.price)
        FROM (SELECT p.price
              FROM purchases p
              WHERE p.userID = u.userID
              ORDER BY p.timestamp DESC
              LIMIT ?    -- whatever number you wnat
             ) p
        ) as avg_price
FROM users u;

为了提高性能,您需要在purchases(userID, timestamp desc, price) 上建立索引。

【讨论】:

  • 感谢您的帮助!我实际上想避免内部查询,因为它们会显着降低性能。但我没想过使用索引,这是个好主意。
【解决方案2】:

您可以使用ROW_NUMBER()窗口函数将购买从最后一个开始排名,然后加入表格users进行聚合:

SELECT u.*, COALESCE(AVG(p.price), 0) avgPrice
FROM users u
LEFT JOIN (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY userID ORDER BY timestamp DESC) rn
  FROM purchases
) p ON p.userID = u.userID AND p.rn <= ?
GROUP BY u.userID

? 更改为您想要的数字n

【讨论】:

  • 这太完美了,谢谢!顺便说一句,如果我希望输出表也包含最后一次购买时间戳的列,我需要更改吗?我尝试在开始时将 p.timestamp 添加到列列表中,但它不起作用。
  • @Ido 使用 MAX(p.timestamp).
猜你喜欢
  • 2023-03-26
  • 2021-06-18
  • 2013-06-01
  • 2015-10-25
  • 1970-01-01
  • 2021-02-25
  • 1970-01-01
  • 2021-04-23
  • 2015-01-17
相关资源
最近更新 更多