【问题标题】:How to create a table that loops over data in Postgres如何在 Postgres 中创建一个循环遍历数据的表
【发布时间】:2019-10-15 09:35:20
【问题描述】:

我想创建一个表,该表返回给定一周内的前 10 个聚合 cons_name,并且每天重复。

因此,对于 2019 年 5 月 29 日,它将以 2019 年 5 月 22 日的总和拉到前 10 名 cons_name

然后,对于 2019 年 5 月 28 日,前 10 名 cons_name 的总和回到 2019 年 5 月 21 日。

从 7 天到 2018 年 12 月 1 日的前 10 名表格。

我可以将简单的代码追溯到 7 天,但是我尝试过 Windows 无济于事。

SELECT cons_name,
       pricedate,
       sum(shadow)
FROM spp.rtbinds
WHERE pricedate >= current_date - 7
GROUP BY cons_name, shadow, pricedate
ORDER BY shadow asc
LIMIT 10

这个查询生成下面的输出

cons_name       pricedate               sum
"TEMP17_24078"  "2019-05-28 00:00:00"   "-1473.29723333333"
"TEMP17_24078"  "2019-05-28 00:00:00"   "-1383.56638333333"
"TMP175_24736"  "2019-05-23 00:00:00"   "-1378.40504166667"
"TMP159_24149"  "2019-05-23 00:00:00"   "-1328.847675"
"TMP397_24836"  "2019-05-23 00:00:00"   "-1221.19560833333"
"TEMP17_24078"  "2019-05-28 00:00:00"   "-1214.9914"
"TMP175_24736"  "2019-05-23 00:00:00"   "-1123.83254166667"
"TEMP72_22893"  "2019-05-29 00:00:00"   "-1105.93840833333"
"TMP164_23704"  "2019-05-24 00:00:00"   "-1053.051375"
"TMP175_24736"  "2019-05-27 00:00:00"   "-1043.52104166667"

我想要一个表格和函数,它返回一周前每天前 10 名的表格。

【问题讨论】:

  • 一些具有预期输出的示例数据会有所帮助。

标签: sql postgresql


【解决方案1】:

使用窗口函数可以让您走上正轨,但您应该在documentation 中进一步阅读有关可能性的信息。

这里有多个问题需要解决:

  1. 数据中的空白(缺少 pricedate)无法让我们获得正确的行数 (7) 来计算总和
  2. 对于计算本身,我们需要所有数据行,因此不能使用WHERE 子句来限制可见
  3. 为了每天选择前 10 名,我们必须为每个分区生成一个行号,因为 LIMIT 子句不能应用于每个组

这就是我想出以下 CTE 的原因:

  1. CTE days:生成无间隙日期系列并标记可见天数
  2. CTE dailyLEFT JOIN 生成日期的数据并生成每日总和(并处理 NULL 条目)
  3. CTE calc:产生累计和
  4. CTE 编号:生成每天重置的行号
  5. 选择实际可见的行并将它们限制为最大。每天 10 个

因此对于特定的一周(2019-05-26 - 2019-06-01),查询将如下所示:

WITH
    days (c_day, c_visible, c_lookback) as (
        SELECT gen::date, (CASE WHEN gen::date < '2019-05-26' THEN false ELSE true END), gen::date - 6
        FROM generate_series('2019-05-26'::date - 6, '2019-06-01'::date, '1 day'::interval) AS gen
    ),
    daily (cons_name, pricedate, shadow_sum) AS (
        SELECT
            r.cons_name,
            r.pricedate::date,
            coalesce(sum(r.shadow), 0)
        FROM days
        LEFT JOIN spp.rtbinds AS r ON (r.pricedate::date = days.c_day)
        GROUP BY 1, 2
    ),
    calc (cons_name, pricedate, shadow_sum) AS (
        SELECT
            cons_name,
            pricedate,
            sum(shadow_sum) OVER (PARTITION BY cons_name ORDER BY pricedate ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)
        FROM daily
    ),
    numbered (cons_name, pricedate, shadow_sum, position) AS (
        SELECT
            calc.cons_name,
            calc.pricedate,
            calc.shadow_sum,
            ROW_NUMBER() OVER (PARTITION BY calc.pricedate ORDER BY calc.shadow_sum DESC)
        FROM calc
    )
SELECT
    days.c_lookback,
    numbered.cons_name,
    numbered.shadow_sum
FROM numbered
INNER JOIN days ON (days.c_day = numbered.pricedate AND days.c_visible)
WHERE numbered.position < 11
ORDER BY numbered.pricedate DESC, numbered.shadow_sum DESC;

生成测试数据的在线示例:https://dbfiddle.uk/?rdbms=postgres_11&fiddle=a83a52e33ffea3783207e6b403bc226a

示例输出:

 c_lookback |  cons_name   |    shadow_sum    
------------+--------------+------------------
 2019-05-26 | TMP400_27000 | 4578.04474575352
 2019-05-26 | TMP700_25000 | 4366.56857151864
 2019-05-26 | TMP200_24000 | 3901.50325547671
 2019-05-26 | TMP400_24000 | 3849.39595793188
 2019-05-26 | TMP700_28000 | 3763.51693260809
 2019-05-26 | TMP600_26000 | 3751.72016620729
 2019-05-26 | TMP500_28000 | 3610.75970225036
 2019-05-26 | TMP300_26000 | 3598.36888491176
 2019-05-26 | TMP600_27000 | 3583.89777677553
 2019-05-26 | TMP300_21000 | 3556.60386707587
 2019-05-25 | TMP400_27000 | 4687.20302128047
 2019-05-25 | TMP200_24000 | 4453.61603102228
 2019-05-25 | TMP700_25000 | 4319.10566615313
 2019-05-25 | TMP400_24000 | 4039.01832416654
 2019-05-25 | TMP600_27000 | 3986.68667223025
 2019-05-25 | TMP600_26000 | 3879.92447655788
 2019-05-25 | TMP700_28000 | 3632.56970774056
 2019-05-25 | TMP800_25000 |  3604.1630071504
 2019-05-25 | TMP600_28000 | 3572.50801157858
 2019-05-25 | TMP500_27000 | 3536.57885829499
 2019-05-24 | TMP400_27000 | 5034.53660146287
 2019-05-24 | TMP200_24000 | 4646.08844632655
 2019-05-24 | TMP600_26000 |  4377.5741555281
 2019-05-24 | TMP700_25000 | 4321.11906399066
 2019-05-24 | TMP400_24000 | 4071.37184911687
 2019-05-24 | TMP600_25000 | 3795.00857752701
 2019-05-24 | TMP700_26000 |  3518.6449117614
 2019-05-24 | TMP600_24000 | 3368.15348120732
 2019-05-24 | TMP200_25000 | 3305.84444172308
 2019-05-24 | TMP500_28000 | 3162.57388606668
 2019-05-23 | TMP400_27000 | 4057.08620966971
 2019-05-23 | TMP700_26000 | 4024.11812392669
...

【讨论】:

  • 谢谢,这肯定有帮助。如何在特定日期运行查询?说,“2019-02-07”
  • 提供了一个更好的查询版本,它允许您在第一个 CTE 中设置 from - to 日期,其余的会被调整自动地。对于单日计算,只需将所有日期常量设置为该日期。
  • 谢谢!我收到一个错误错误:列“r.priceate”必须出现在 GROUP BY 子句中或用于聚合函数第 7 行:SELECT r.cons_name, r.priceate, sum(r.shadow)
  • 对不起,o型。将第二列添加到GROUP BY' in CTE daily`。
  • 所以代码生成的东西很棒,但是有没有办法让它每天循环并列出每天的前 10 名,然后创建一个列是 7 天“回顾”日期?有道理?因此,我们所拥有的 2019-06-01 是回溯日期,并且生成的任何 cons_name 总和都将具有“2019-06-01”而不是价格日期。除此之外,还有一个从 2018 年 12 月 1 日开始循环的列表。我知道更多曲线球!
猜你喜欢
  • 2018-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多