获取自动态系列天数以来具有最高审阅计数的应用程序

wf82jlnq  于 2021-07-24  发布在  Java
关注(0)|答案(3)|浏览(415)

我有两张table, apps 以及 reviews (为便于讨论而简化):

应用程序表

  1. id int

评论表

  1. id int
  2. review_date date
  3. app_id int (foreign key that points to apps)

2个问题:

1. 如何编写查询/函数来回答以下问题:

给出了一系列最早的日期 reviews.review_date 最新消息 reviews.review_date (递增一天),对于每个日期, D ,如果应用程序最早的评论是在或晚于 D ?
如果给定明确的日期,我想我知道如何编写查询:

  1. SELECT
  2. apps.id,
  3. count(reviews.*)
  4. FROM
  5. reviews
  6. INNER JOIN apps ON apps.id = reviews.app_id
  7. group by
  8. 1
  9. having
  10. min(reviews.review_date) >= '2020-01-01'
  11. order by 2 desc
  12. limit 10;

但我不知道如何在给定所需的日期序列的情况下动态查询这些信息,并在单个视图中编译所有这些信息。

2. 对这些数据进行建模的最佳方法是什么?

最好能在每个日期的时候都有一份评论以及 app_id . 到现在为止,我在想一些可能看起来像:

  1. ... 2020-01-01_app_id | 2020-01-01_review_count | 2020-01-02_app_id | 2020-01-02_review_count ...

但我想知道有没有更好的办法。将数据拼接在一起似乎也是一项挑战。

flmtquvp

flmtquvp1#

我缺少的是横向连接。我可以通过以下方法实现我想要的:

  1. select
  2. review_windows.review_window_start,
  3. id,
  4. review_total,
  5. earliest_review
  6. from
  7. (
  8. select
  9. date_trunc('day', review_windows.review_windows) :: date as review_window_start
  10. from
  11. generate_series(
  12. (
  13. SELECT
  14. min(reviews.review_date)
  15. FROM
  16. reviews
  17. ),
  18. (
  19. SELECT
  20. max(reviews.review_date)
  21. FROM
  22. reviews
  23. ),
  24. '1 year'
  25. ) review_windows
  26. order by
  27. 1 desc
  28. ) review_windows
  29. left join lateral (
  30. SELECT
  31. apps.id,
  32. count(reviews.*) as review_total,
  33. min(reviews.review_date) as earliest_review
  34. FROM
  35. reviews
  36. INNER JOIN apps ON apps.id = reviews.app_id
  37. where
  38. reviews.review_date >= review_windows.review_window_start
  39. group by
  40. 1
  41. having
  42. min(reviews.review_date) >= review_windows.review_window_start
  43. order by
  44. 2 desc,
  45. 3 desc
  46. limit
  47. 2
  48. ) apps_most_reviews on true;
展开查看全部
0ejtzxu1

0ejtzxu12#

我想这就是你想要的:

postgres 13或更新

  1. WITH cte AS ( -- MATERIALIZED
  2. SELECT app_id, min(review_date) AS earliest_review, count(*)::int AS total_ct
  3. FROM reviews
  4. GROUP BY 1
  5. )
  6. SELECT *
  7. FROM (
  8. SELECT generate_series(min(review_date)
  9. , max(review_date)
  10. , '1 day')::date
  11. FROM reviews
  12. ) d(review_window_start)
  13. LEFT JOIN LATERAL (
  14. SELECT total_ct, array_agg(app_id) AS apps
  15. FROM (
  16. SELECT app_id, total_ct
  17. FROM cte c
  18. WHERE c.earliest_review >= d.review_window_start
  19. ORDER BY total_ct DESC
  20. FETCH FIRST 1 ROWS WITH TIES -- new & hot
  21. ) sub
  22. GROUP BY 1
  23. ) a ON true;
  24. ``` `WITH TIES` 便宜一点。在postgres 13中添加(目前为测试版)。请参见:
  25. 大于或等于all()且等于max()速度
  26. #### 12岁及以上

WITH cte AS ( -- MATERIALIZED
SELECT app_id, min(review_date) AS earliest_review, count(*)::int AS total_ct
FROM reviews
GROUP BY 1
)
SELECT *
FROM (
SELECT generate_series(min(review_date)
, max(review_date)
, '1 day')::date
FROM reviews
) d(review_window_start)
LEFT JOIN LATERAL (
SELECT total_ct, array_agg(app_id) AS apps
FROM (
SELECT total_ct, app_id
, rank() OVER (ORDER BY total_ct DESC) AS rnk
FROM cte c
WHERE c.earliest_review >= d.review_window_start
) sub
WHERE rnk = 1
GROUP BY 1
) a ON true;

  1. db<>在这里摆弄
  2. 同上,但没有 `WITH TIES` .
  3. 我们不需要牵扯到table `apps` 完全。table `reviews` 有我们需要的所有信息。
  4. cte `cte` 计算每个应用程序的最早评论和当前总计数。cte避免了重复计算。应该能帮上不少忙。
  5. 它总是在postgres 12之前具体化,并且应该在postgres 12中自动具体化,因为它在主查询中被多次使用。否则你可以添加关键字 `MATERIALIZED` 12年级或更高的时候强迫它。请参见:
  6. 如何在加入/下推到外部服务器之前强制计算子查询
  7. 优化的 `generate_series()` call生成从最早到最新的一系列日期。请参见:
  8. postgresql中生成两个日期之间的时间序列
  9. postgres中加入对generate\u系列的计数查询,并将空值检索为“0
  10. 最后是 `LEFT JOIN LATERAL` 你已经发现了。但是由于多个应用程序可以获得最多的评论,所以检索所有的获奖者,可以是0-n个应用程序。该查询将所有每日获奖者聚合到一个数组中,因此我们每行得到一个结果 `review_window_start` . 或者,定义决胜局最多只能获得一个赢家。请参见:
  11. postgresql中,横向查询和子查询有什么区别?
展开查看全部
nuypyhwy

nuypyhwy3#

如果您正在寻找提示,那么以下是一些:
你知道吗 generate_series() 以及如何使用它来组成一个给定开始和结束日期的日期表?如果没有,那么在这个网站上有很多例子。
要在任何给定日期回答此问题,您只需为每个应用程序设置两个度量值,其中只有一个度量值用于将一个应用程序与其他应用程序进行比较。您在第1部分中的查询表明您知道这两个度量是什么。
提示1和2应该足以完成这项任务。我唯一能补充的是,你不用担心让数据库做“太多的工作”,这就是它要做的。如果它做得不够快,那么你可以考虑优化,但是在你进入那一步之前,集中精力得到你想要的答案。
请评论,如果你需要进一步澄清这一点。

相关问题