【问题标题】:Convert comma delimited values in a column into rows将列中的逗号分隔值转换为行
【发布时间】:2021-09-06 00:15:46
【问题描述】:

我想将逗号分隔的值转换为 Redshift 中的行

例如:

store  |location |products
-----------------------------
1      |New York |fruit, drinks, candy...

想要的输出是:

store  |location | products
------------------------------- 
1      |New York | fruit        
1      |New York | drinks         
1      |New York | candy     

是否有任何简单的解决方案可以根据分隔符拆分单词并转换为行?我正在研究这个解决方案,但它还不起作用:https://help.looker.com/hc/en-us/articles/360024266693-Splitting-Strings-into-Rows-in-the-Absence-of-Table-Generating-Functions

任何建议将不胜感激。

【问题讨论】:

  • 强烈建议不要在 Redshift 中这样做。它应该在数据加载到数据库之前完成。 Redshift 在这方面的能力很差。
  • 谢谢@MatBailie,如果 Redshift 不适合此任务,我也可以使用 MySQL
  • 如果您不知道您使用的是 MySQL 还是 Redshift,那么您已经遇到了问题。它们用于非常不同的目的。这就像在拖拉机或卡车之间挑选;它们都是带有大引擎的车辆,但你不应该用卡车耕地或用拖拉机拖运货物......
  • MYSQL也可以 MySQL版本准确吗?

标签: mysql sql amazon-redshift denormalized


【解决方案1】:

如果你知道值的最大数量,我想你可以split_part()

select t.store, t.location, split_part(products, ',', n.n) as product
 from t join
      (select 1 as n union all
       select 2 union all
       select 3 union all
       select 4
      ) n
      on split_part(products, ',', n.n) <> '';
 

你也可以使用:

select t.store, t.location, split_part(products, ',', 1) as product
from t 
union all
select t.store, t.location, split_part(products, ',', 2) as product
from t 
where split_part(products, ',', 2) <> ''
union all
select t.store, t.location, split_part(products, ',', 3) as product
from t 
where split_part(products, ',', 3) <> ''
union all
select t.store, t.location, split_part(products, ',', 4) as product
from t 
where split_part(products, ',', 4) <> ''
union all
. . .

【讨论】:

    【解决方案2】:

    首先,您需要创建一个数字表,因为连接另一个表是 redshift 将一行转换为多行的唯一方法(没有展平或非嵌套功能)。

    • 例如,一个有 1024 行的表,其中的值为 1..1024

    然后你可以加入并使用split_part()

    SELECT
      yourTable.*,
      numbers.ordinal,
      split_part(your_table.products, ',', numbers.ordinal)  AS product
    FROM
      yourTable
    INNER JOIN
      numbers
        ON  numbers.ordinal >= 1
        AND numbers.ordinal <= regexp_count(your_table.products, ',') + 1
    

    但是……

    Redshift 在预测所需行数方面很糟糕。它将加入整个 1024 行,然后拒绝不匹配的行。

    它的表现就像一条狗。

    因为设计假设是这样的处理总是在加载到 Redshift 之前完成。

    【讨论】:

      【解决方案3】:
      CREATE TABLE temptbl  
      (
          store INT,
          location  NVARCHAR(MAX),
          products NVARCHAR(MAX)
      )
      
      
      
      INSERT temptbl   SELECT 1,  'New York', 'Fruit, drinks, candy'
      

      创建表时的输出

      select * from temptbl
      
      
      ;WITH tmp(store, location, DataItem, products) AS
      (
          SELECT
              store,
              location,
              LEFT(products, CHARINDEX(',', products + ',') - 1),
              STUFF(products, 1, CHARINDEX(',', products + ','), '')
          FROM temptbl
          UNION all
      
          SELECT
              store  ,
              location,
              LEFT(products, CHARINDEX(',', products + ',') - 1),
              STUFF(products, 1, CHARINDEX(',', products + ','), '')
          FROM tmp
          WHERE
              products > ''
      )
      
      SELECT
          store,
          location,
          DataItem
      FROM tmp
      

      您希望在多行中使用逗号分隔值: 运行以上命令后你想要的输出:

      希望你找到你的解决方案:)))

      【讨论】:

      • 我怀疑它在 MySQL 或 Redshift 上运行
      • CHARINDEX 错误需要查找 CHARINDEX 的别名
      • 您已经为 Microsoft SQL Server 编写了它。 OP 要求 MySQL 或 Redshift ......因此必须先评论;这不是对实际提出的问题的回答。
      【解决方案4】:

      MYSQL 也可以


      CREATE TABLE test
      SELECT 1 store, 'New York' location, 'fruit,drinks,candy' products;
      
      SELECT store, location, product
      FROM test
      CROSS JOIN JSON_TABLE(CONCAT('["', REPLACE(products, ',', '","'), '"]'),
                            "$[*]" COLUMNS (product VARCHAR(255) PATH "$")) jsontable
      
      store location product
      1 New York fruit
      1 New York drinks
      1 New York candy

      db小提琴here

      【讨论】:

        【解决方案5】:

        在 MySQL 中,这将适用于最多四个逗号分隔的值。注意UNION,而不是UNION ALLFiddle

        SELECT store, location,  
               TRIM(SUBSTRING_INDEX(products, ',', 1)) product
          FROM inventory
         UNION 
        SELECT store, location, 
               TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(products, ',', 2), ',', -1))
          FROM inventory
         UNION 
        SELECT store, location, 
               TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(products, ',', 3), ',', -1))
          FROM inventory
         UNION 
        SELECT store, location, 
               TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(products, ',', 4), ',', -1))
          FROM inventory
        

        我会附和其他人所说的话。恕我直言,逗号分隔值是一种糟糕的表格设计。

        • 这会导致丑陋的 SQL。能够阅读和推理 SQL 非常重要。清晰总是赢家。
        • 而且,AWS 股东会因此而爱上你,因为你会在 redshift 上花费很多额外的钱。

        【讨论】:

          猜你喜欢
          • 2012-12-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-21
          • 1970-01-01
          • 2014-09-26
          • 1970-01-01
          相关资源
          最近更新 更多