Redshift 按时间将具有相同数据的分区分开
Redshift separate partitions with identical data by time
我在 Redshift table 中有数据,例如 product_id、价格和 time_of_purchase。我想为自上次购买以来每次价格变化创建分区。在这种情况下,一件商品的价格可能会回到以前的价格,但我需要将其作为一个单独的分区,例如:
注意价格是 2 美元,然后涨到 3 美元,然后又回到 2 美元。如果我做类似的事情(按 [=17= 分区],按 time_of_purchase 排序价格),那么最后一行将与前两行分区,这是我不想要的。我怎样才能正确地做到这一点,以便获得三个独立的分区?
用lag()
得到前一个值再求一个累加和:
select t.*,
sum(case when prev_price = price then 0 else 1 end) over
(partition by product_id order by time_of_purchase) as partition_id
from (select t.*,
lag(price) over (partition by product_id order by time_of_purchase) as prev_price
from t
) t
与@Gordon Linoff 不同,我更喜欢使用 WITH 子句一步步完成...
并且,正如我在其他 post 中多次提到的那样 - 请以 copy-paste 就绪格式添加您的示范数据,这样我们就不必 copy-paste 您的示例.
我喜欢以self-contained微型演示格式添加我的示例,输入数据已经在我的post中,这样每个人都可以玩它,这就是为什么..
WITH
-- your input, typed manually ....
indata(product_id,price,tm_of_p) AS (
SELECT 1,2.00,TIMESTAMP '2020-09-14 09:00'
UNION ALL SELECT 1,2.00,TIMESTAMP '2020-09-14 10:00'
UNION ALL SELECT 1,3.00,TIMESTAMP '2020-09-14 11:00'
UNION ALL SELECT 1,3.00,TIMESTAMP '2020-09-14 12:00'
UNION ALL SELECT 1,2.00,TIMESTAMP '2020-09-14 13:00'
)
,
with_change_counter AS (
SELECT
*
, CASE WHEN LAG(price) OVER(PARTITION BY product_id ORDER BY tm_of_p) <> price
THEN 1
ELSE 0
END AS chg_count
FROM indata
)
SELECT
product_id
, price
, tm_of_p
, SUM(chg_count) OVER(PARTITION BY product_id ORDER BY tm_of_p) AS session_id
FROM with_change_counter;
-- out product_id | price | tm_of_p | session_id
-- out ------------+-------+---------------------+------------
-- out 1 | 2.00 | 2020-09-14 09:00:00 | 0
-- out 1 | 2.00 | 2020-09-14 10:00:00 | 0
-- out 1 | 3.00 | 2020-09-14 11:00:00 | 1
-- out 1 | 3.00 | 2020-09-14 12:00:00 | 1
-- out 1 | 2.00 | 2020-09-14 13:00:00 | 2
我在 Redshift table 中有数据,例如 product_id、价格和 time_of_purchase。我想为自上次购买以来每次价格变化创建分区。在这种情况下,一件商品的价格可能会回到以前的价格,但我需要将其作为一个单独的分区,例如:
注意价格是 2 美元,然后涨到 3 美元,然后又回到 2 美元。如果我做类似的事情(按 [=17= 分区],按 time_of_purchase 排序价格),那么最后一行将与前两行分区,这是我不想要的。我怎样才能正确地做到这一点,以便获得三个独立的分区?
用lag()
得到前一个值再求一个累加和:
select t.*,
sum(case when prev_price = price then 0 else 1 end) over
(partition by product_id order by time_of_purchase) as partition_id
from (select t.*,
lag(price) over (partition by product_id order by time_of_purchase) as prev_price
from t
) t
与@Gordon Linoff 不同,我更喜欢使用 WITH 子句一步步完成...
并且,正如我在其他 post 中多次提到的那样 - 请以 copy-paste 就绪格式添加您的示范数据,这样我们就不必 copy-paste 您的示例.
我喜欢以self-contained微型演示格式添加我的示例,输入数据已经在我的post中,这样每个人都可以玩它,这就是为什么..
WITH
-- your input, typed manually ....
indata(product_id,price,tm_of_p) AS (
SELECT 1,2.00,TIMESTAMP '2020-09-14 09:00'
UNION ALL SELECT 1,2.00,TIMESTAMP '2020-09-14 10:00'
UNION ALL SELECT 1,3.00,TIMESTAMP '2020-09-14 11:00'
UNION ALL SELECT 1,3.00,TIMESTAMP '2020-09-14 12:00'
UNION ALL SELECT 1,2.00,TIMESTAMP '2020-09-14 13:00'
)
,
with_change_counter AS (
SELECT
*
, CASE WHEN LAG(price) OVER(PARTITION BY product_id ORDER BY tm_of_p) <> price
THEN 1
ELSE 0
END AS chg_count
FROM indata
)
SELECT
product_id
, price
, tm_of_p
, SUM(chg_count) OVER(PARTITION BY product_id ORDER BY tm_of_p) AS session_id
FROM with_change_counter;
-- out product_id | price | tm_of_p | session_id
-- out ------------+-------+---------------------+------------
-- out 1 | 2.00 | 2020-09-14 09:00:00 | 0
-- out 1 | 2.00 | 2020-09-14 10:00:00 | 0
-- out 1 | 3.00 | 2020-09-14 11:00:00 | 1
-- out 1 | 3.00 | 2020-09-14 12:00:00 | 1
-- out 1 | 2.00 | 2020-09-14 13:00:00 | 2