【问题标题】:Postgres: Query to compare Data with previous DataPostgres:查询以将数据与以前的数据进行比较
【发布时间】:2017-04-25 12:49:59
【问题描述】:

我有一个主表,我的所有结果都将写入其中。 每个将被检查的对象都由 item_id 标识:

Checkdate     item_id    Price Cat A    Price Cat B
2017-04-25    1          29.99          84.99
2017-04-24    1          39.99          89.99
2017-04-23    1          39.99          91.99
2017-04-25    2          42.99          88.99
2017-04-23    2          41.99          81.99
2017-04-22    2          50.99          81.99
2017-04-21    2          42.99          81.99

在 postgres 查询中,我选择 current_date = checkdate 的所有结果以提供最新数据:

Item    Price Cat A      Price Cat B
1       29.99            84.99
2       42.99            88.99

到目前为止,这对我来说不是问题。但现在我想将这些结果与以前的结果进行比较。类似的东西:

Item    Price Cat A    Price Cat A Before   Price Cat B    Price Cat B Before
1       29.99          39.99                84.99          89.99
2       42.99          41.99                88.99          81.99

但我不知道该怎么做。这些项目并非每天都存在(例如,项目 2 在 2017-04-24 不存在)。

有人可以帮我吗?

【问题讨论】:

  • 条件current_date = checkdate 似乎暗示您每天检查所有(当前)项目。是这样吗?闻起来很有趣……
  • 这有什么好笑的?该应用程序每天捕获一次最新数据并将其存储在数据库中。上面的查询将被 web 服务调用以获取最新数据(具有缓存功能)。此处需要 current_date,因为有时(如前所述)项目不存在(但明天可能会再次存在)。

标签: postgresql aggregate


【解决方案1】:
select
    item_id,
    min(price_cat_a) filter (where rn = 1) as a,
    min(price_cat_a) filter (where rn = 2) as a_before,
    min(price_cat_b) filter (where rn = 1) as b,
    min(price_cat_b) filter (where rn = 2) as b_before
from (
    select
        item_id, price_cat_a, price_cat_b,
        row_number() over (partition by item_id order by checkdate desc) as rn
    from t
    where checkdate <= current_date
) s
where rn <= 2
group by item_id
;
 item_id |   a   | a_before |   b   | b_before 
---------+-------+----------+-------+----------
       1 | 29.99 |    39.99 | 84.99 |    89.99
       2 | 42.99 |    41.99 | 88.99 |    81.99

【讨论】:

    【解决方案2】:

    您可以使用横向连接:

    SELECT today.item_id,
           today."Price Cat A",
           before."Price Cat A" AS "Price Cat A Before",
           today."Price Cat B",
           before."Price Cat B" AS "Price Cat B Before"
    FROM main today
       CROSS JOIN LATERAL
         (SELECT "Price Cat A",
                 "Price Cat B"
          FROM main
          WHERE item_id = today.item_id
            AND "Checkdate" < today."Checkdate"
          ORDER BY "Checkdate" DESC
          LIMIT 1
         ) before
    WHERE today."Checkdate" = current_date
    ORDER BY today.item_id;
    

    【讨论】:

      【解决方案3】:

      这些项目并非每天都存在——因此,您的原始查询也有错误(即它不会包含您的所有项目)。

      如果您正在查找最后一个(和倒数第二个)checkdate,则无需使用current_date(除非您的表中可能有未来的数据;在这种情况下,只需将where checkdate &lt;= current_date 附加到过滤掉它们)。

      找到最后一行(在其组内,即在您的情况下为item_id)是典型的 问题,而使用lag() window function 可以轻松找到倒数第二行:

      select   distinct on (item_id)
               item_id,
               price_cat_a,
               price_cat_a_before,
               price_cat_b,
               price_cat_b_before
      from     (select *,
                       lag(price_cat_a) over w price_cat_a_before,
                       lag(price_cat_b) over w price_cat_b_before
                from   t
                window w as (partition by item_id order by checkdate)) t
      order by item_id, checkdate desc
      

      http://rextester.com/AGZ99646

      【讨论】:

      • 呸,这对我来说真的很复杂。你能解释一下关键字“window”、“partition by”是什么意思吗?还有第一行(在 (item_id) 上不同)?
      • @user2622344 这些是window function 调用的一部分。在链接的资源中阅读有关它们的更多信息。
      猜你喜欢
      • 2019-02-15
      • 2020-09-25
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多