问题描述
我目前正在将 Postgresql 代码从我们现有的 DWH 迁移到新的 Redshift DWH,并且很少有查询不兼容。 我有一个表,它在一行中包含 id、start_week、end_week 和 orders_each_week。我正在尝试在 start_week 和 end_week 之间生成一个连续的系列,以便我在给定的时间线之间将每周的行分开。
例如, 这是它在表格中的显示方式
+----+------------+----------+------------------+
| ID | start_week | end_week | orders_each_week |
+----+------------+----------+------------------+
| 1 | 3 | 5 | 10 |
+----+------------+----------+------------------+
这就是我想要的
+----+------+--------+
| ID | week | orders |
+----+------+--------+
| 1 | 3 | 10 |
+----+------+--------+
| 1 | 4 | 10 |
+----+------+--------+
| 1 | 5 | 10 |
+----+------+--------+
SELECT
id,generate_series(start_week::BIGINT,end_week::BIGINT) AS demand_weeks
FROM client_demand
WHERE createddate::DATE >= '2021-01-01'
[0A000][500310] Amazon 无效操作:Redshift 表不支持指定的类型或函数(每个 INFO 消息一个)。 [01000] 不支持函数“generate_series(bigint,bigint)”。
所以基本上我试图在两个数字之间找到一个连续的系列,但我找不到任何解决方案,非常感谢这里的任何帮助。谢谢
解决方法
Gordon Linoff 展示了一种非常常用的方法来执行此操作,这种方法的优点是该过程不会生成尚不存在的“行”。这可以使其比动态生成数据的方法更快。但是,您需要有一个包含大约正确行数的表格,但情况并非总是如此。他还表明,这个数字系列需要与您的数据交叉连接才能执行您需要的功能。
如果您需要在不使用现有表格的情况下生成大量数字,有多种方法可以做到这一点。这是我的方法:
WITH twofivesix AS (
SELECT
p0.n
+ p1.n * 2
+ p2.n * POWER(2,2)
+ p3.n * POWER(2,3)
+ p4.n * POWER(2,4)
+ p5.n * POWER(2,5)
+ p6.n * POWER(2,6)
+ p7.n * POWER(2,7)
as n
FROM
(SELECT 0 as n UNION SELECT 1) p0,(SELECT 0 as n UNION SELECT 1) p1,(SELECT 0 as n UNION SELECT 1) p2,(SELECT 0 as n UNION SELECT 1) p3,(SELECT 0 as n UNION SELECT 1) p4,(SELECT 0 as n UNION SELECT 1) p5,(SELECT 0 as n UNION SELECT 1) p6,(SELECT 0 as n UNION SELECT 1) p7
),fourbillion AS (
SELECT (a.n * POWER(256,3) + b.n * POWER(256,2) + c.n * 256 + d.n) as n
FROM twofivesix a,twofivesix b,twofivesix c,twofivesix d
)
SELECT ...
此示例生成了一大堆数字 (4B),但您可以通过更改表交叉连接的次数和添加 where 子句(如 Gordon Linoff 所做的)来扩展或减少系列中的数字。我不希望你需要一个接近这么长的列表,但想展示如何使用它来制作非常长的系列。 (如果这对您更有意义,您也可以使用以 10 为底的写法。)
因此,如果您有一个包含更多行且需要编号的表,那么这可能是最快的方法,但如果您没有这样的表或表长度随时间变化,您可能需要这种纯 SQL 方法。
> ,在 Redshift 不支持的众多 Postgres 功能中,有 generate_series()
(主节点除外)。你可以自己生成一个。
如果您在 Redshift 中有一个包含足够多行的表,那么我发现这种方法有效:
with n as (
select row_number() over () - 1 as n
from client_demand cd
)
select cd.id,cd.start_week + n.n as week,cd.orders_each_week
from client_demand cd join
n
on n.n <= (end_week - start_week);
这假设您有一个包含足够行数的表来为 on
子句生成足够的数字。如果表真的很大,则在 limit 100
CTE 中添加类似 n
的内容以限制大小。
如果只有少数值,您可以使用:
select 0 as n union all
select 1 as n union all
select 2 as n