Redshift:生成一系列数字

问题描述

我目前正在将 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 

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...