这可能有点复杂,所以请耐心等待。我希望在当前看起来像这样的表中创建一个新列 free_duration,当按月份升序按国家/地区和产品分组时 -
month country product stock
7/1/10 Wakanda Vibranium 7166
8/1/10 Wakanda Vibranium 6189
9/1/10 Wakanda Vibranium 1987
10/1/10 Wakanda Vibranium 98
11/1/10 Wakanda Vibranium 23
12/1/10 Wakanda Vibranium 1
1/1/11 Wakanda Vibranium 29999
2/1/11 Wakanda Vibranium 2314
3/1/11 Wakanda Vibranium 19
对于给定行 x1,新列 free_duration 基本上是 stock 列所在的月数 值小于或等于该行中的库存列值 x1,直到出现更多库存(即库存值接下来增加)。
在示例中,对于第 1 行,按月份升序排列,7 月 '10 的库存为 7166 - 因此 7 月 '10 的 free_duration 值应为 5,因为连续 5 个月,行中的库存列值小于 7166 1,直到达到下一个更高的值。同样,对于 2010 年 12 月第 6 行,可用库存为 1,并且考虑到下一个月库存大于 1,free_duration 应为 0。
总而言之,我需要在一列中取一个值,对同一列中所有小于或等于的值进行倒数,直到达到下一个直接更大的值。
我的查询几乎做到了这一点,但有一个逻辑缺陷 - 在每个组中,它最终会计算所有较小的值,并且不会设置限制计数的上限,直到达到下一个更高的值。
WITH ranking AS (SELECT month,
country,
product,
stock,
ROW_NUMBER() OVER (PARTITION BY country, product ORDER BY month) AS rn
FROM data_table),
free_duration_cte AS (SELECT r1.month,
r1.country,
r1.product,
r1.stock,
COALESCE((SELECT COUNT(*)
FROM ranking r2
WHERE r1.country = r2.country
AND r1.product = r2.product
AND r2.rn > r1.rn
AND r2.stock <=
r1.stock), 0) AS free_duration
FROM ranking r1)
SELECT *
FROM free_duration_cte
ORDER BY country, product, month;
我已经尝试了多种其他方法来仅设置上限,最简单的方法是使用 FIRST_VALUE(),这在 Redshift 中是不被接受的。任何有助于做出所需改变的帮助将不胜感激。
这是您要找的吗?
create table table_1 (
month date,
country varchar(16),
product varchar(16),
stock int);
insert into table_1 values
('2010-7-1', 'Wakanda', 'Vibranium', 7166),
('2010-8-1', 'Wakanda', 'Vibranium', 6189),
('2010-9-1', 'Wakanda', 'Vibranium', 1987),
('2010-10-1', 'Wakanda', 'Vibranium', 98),
('2010-11-1', 'Wakanda', 'Vibranium', 23),
('2010-12-1', 'Wakanda', 'Vibranium', 1),
('2011-1-1', 'Wakanda', 'Vibranium', 29999),
('2011-2-1', 'Wakanda', 'Vibranium', 2314),
('2011-3-1', 'Wakanda', 'Vibranium', 19);
with min_local as (
select *,
nvl(min(stock) over(partition by country, product order by month rows between current row and unbounded following), stock) local_min
from table_1),
change as (
select *,
decode(lag(local_min) over(partition by country, product order by month), local_min, 0, 1) change
from min_local),
groups as (
select *,
sum(change) over(partition by country, product order by month rows unbounded preceding) grp
from change)
select month, country, product, stock,
count(*) over(partition by country, product, grp order by month desc rows unbounded preceding) - 1 as free_duration
from groups
order by month;