【问题标题】:Redshift split single dynamic column into multiple rows in new tableRedshift 将单个动态列拆分为新表中的多行
【发布时间】:2018-03-28 19:48:05
【问题描述】:

使用如下表格:

       uid               |            segmentids
-------------------------+----------------------------------------
 f9b6d54b-c646-4bbb-b0ec | 4454918|4455158|4455638|4455878|4455998
 asd7a0s9-c646-asd7-b0ec | 1265899|1265923|1265935|1266826|1266596
 gd3355ff-cjr8-assa-fke0 | 2237557|2237581|2237593
 laksnfo3-kgi5-fke0-b0ec | 4454918|4455158|4455638|4455878

如何创建一个新表:

      uid               |         segmentids
-------------------------+---------------------------
 f9b6d54b-c646-4bbb-b0ec |           4454918
 f9b6d54b-c646-4bbb-b0ec |           1265899
 f9b6d54b-c646-4bbb-b0ec |           2237557
 f9b6d54b-c646-4bbb-b0ec |           4454918
 f9b6d54b-c646-4bbb-b0ec |           4454918
 asd7a0s9-c646-asd7-b0ec |           1265899
 asd7a0s9-c646-asd7-b0ec |           1265923
 asd7a0s9-c646-asd7-b0ec |           1265935 
 asd7a0s9-c646-asd7-b0ec |           1266826
 asd7a0s9-c646-asd7-b0ec |           1266596

段的数量是动态的,可以随每条记录而变化。 我尝试了带分隔符的拆分函数,但它需要字符串中的索引,这里是动态的。

有什么建议吗?

【问题讨论】:

  • 你标记了几个dbms产品,怎么来的?
  • 这里的动态是什么?您在示例中使用 index =1 - 请展示一些不同的示例来解释
  • 我理解这个问题——请将您的标签更改为您正在使用的标签,因为答案完全不同!

标签: sql amazon-redshift


【解决方案1】:

这是 Redshift 的答案,每行最多可处理 10000 个段 id 值。

测试数据

create table test_split (uid varchar(50),segmentids varchar(max));
insert into test_split
    values
      ('f9b6d54b-c646-4bbb-b0ec','4454918|4455158|4455638|4455878|4455998'),
      ('asd7a0s9-c646-asd7-b0ec','1265899|1265923|1265935|1266826|1266596'),
      ('asd7345s9-c646-asd7-b0ec','1235935|1263456|1265675696'),
      ('as345a0s9-c646-asd7-b0ec','12765899|12658883|12777935|144466826|1266226|12345')
;

代码

with ten_numbers as (select 1 as num union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0)
  , generted_numbers AS
(
    SELECT (1000 * t1.num) + (100 * t2.num) + (10 * t3.num) + t4.num AS gen_num
    FROM ten_numbers AS t1
      JOIN ten_numbers AS t2 ON 1 = 1
      JOIN ten_numbers AS t3 ON 1 = 1
      JOIN ten_numbers AS t4 ON 1 = 1
)
  , splitter AS
(
    SELECT *
    FROM generted_numbers
    WHERE gen_num BETWEEN 1 AND (SELECT max(REGEXP_COUNT(segmentids, '\\|') + 1)
                                 FROM test_split)
)
  --select * from splitter;
  , expanded_input AS
(
    SELECT
      uid,
      split_part(segmentids, '|', s.gen_num) AS segment
    FROM test_split AS ts
      JOIN splitter AS s ON 1 = 1
    WHERE split_part(segmentids, '|', s.gen_num) <> ''
)
SELECT * FROM expanded_input;

前 2 个 cte 步骤(ten_numbers 和 generated_numbers)用于生成行数,这是必需的,因为不支持 generate_series

下一步(分割器)只需要行数等于最大分隔符数 + 1(即最大段数)

最后,我们将连接拆分器与输入数据交叉,使用 split_part 获取相关值,然后排除空白部分(这是由行具有

【讨论】:

  • 像魅力一样工作。仍在试图弄清楚如何。我得到了索引部分,但你如何将它与原始表中的 uid 匹配?
  • 为什么我们在十个数字中使用 1000、100 和 10 之类的值?
  • 它正在生成 10000 行输出。 gen_num 每行递增。通常你可以为此使用 generate_series 函数,但这在 redshift 中是不可能的,所以这是一个聪明的解决方法。如果您不需要 10000,那么您可以删除该部分。这样做几乎没有开销。
  • 匹配作为交叉连接完成(FROM test_split AS ts JOIN splitter AS s ON 1 = 1)。每个 test_split 都与每个拆分器行合并。我们只有从 1 到文件中任何位置的最大段数的拆分行。
  • 它很漂亮——在我这个时代,我开始学习价值立即可读的代码。正确的解决方案是在管道中包含一个阶段,以在 spark 或类似中进行功能转换。那么这个困难的逻辑就变成了df.withColumn("segment_id", functions.explode("seg_array")),在通过select(split(col("segmentids"),"|").alias("seg_array"))将分隔列转换为任意数组之后
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多