UNNEST 多个值?

Posted

技术标签:

【中文标题】UNNEST 多个值?【英文标题】:UNNEST Multiple Values? 【发布时间】:2018-09-04 17:21:21 【问题描述】:

我正在尝试用另一张桌子制作一张桌子。原始表有一行如下所示:

------------------------
| col1 | col 2 | col 3 |
------------------------
| item | a,b,c | 1,2,3 |
------------------------

我正在尝试获取该行,并将其放入如下表格中:

------------------------
| col1 | col 2 | col 3 |
------------------------
| item |   a   |   1   |
------------------------
| item |   b   |   2   |
------------------------
| item |   c   |   3   |
------------------------

所以基本上我试图同时 UNNEST 两个逗号分隔的行。到目前为止,我想出的最好方法是单独 UNNEST 每一列,然后尝试合并两个结果表(我也在努力解决这个问题),但理想情况下我希望一步完成。

这是我一次对 UNNEST 一行的查询:

SELECT
  col1, col2, col3
FROM 
  tableName,
UNNEST(SPLIT(col2)) AS col2

这是我尝试将 UNNEST 作为子查询进行的尝试,但它提供了大量结果:

SELECT sub.*
FROM (
  SELECT
    col1, col2, col3 AS col3
  FROM 
    tableName,
  UNNEST(SPLIT(col2)) AS col2
  WHERE
    randomCol = 'something'
  ) sub,
UNNEST(SPLIT(sub.col3)) AS col3

【问题讨论】:

您使用的是哪种 DBMS 产品? Postgres? 它实际上是一个自定义 DBMS,但符合 SQL 2011 标准。 【参考方案1】:

SQL 标准允许将多个值传递给unnest() 函数。

所以以下应该有效(并且在 Postgres 中有效)

select d.col1, 
       t.*
from data d
  cross join unnest(string_to_array(d.col2, ','), string_to_array(d.col3, ',')) as t(col1, col2) 

这也可以正确处理列表中不同数量的元素。

但是,我不知道您的专有 DBMS 是否支持该功能。

在线示例:http://rextester.com/XPN48947

【讨论】:

【参考方案2】:

您可以使用unnest(split(col)) 策略,但不要交叉连接两个列。您的回答暗示了逗号分隔值的隐含顺序,因此您需要建立一个字段(下面的RowNumber)来指示此顺序。

with Expanded2 as (
  select
    tableName.col1,
    col2.col2,
    row_number() over (partition by col1 order by 1) RowNumber
  from
    tableName,
    unnest(split(col2)) col2
), Expanded3 as (
  select
    tableName.col1,
    col3.col3,
    row_number() over (partition by col1 order by 1) RowNumber
  from
    tableName,
    unnest(split(col3)) col3
)
select
  Expanded2.col1,
  Expanded2.col2,
  Expanded3.col3
from
  Expanded2
  full outer join Expanded3 on 
    Expanded2.col1 = Expanded3.col1
    and Expanded2.RowNumber = Expanded3.RowNumber

我不确定您的 rdbms 如何有效地处理空窗口分区。以上适用于 PostgreSQL。 SQL Server 需要order by (select null)。嗯嗯。

【讨论】:

【参考方案3】:

通过说原始表有“一行”:你的意思是一个吗?如果是,这可以解决问题:

with 
num_rows_ as (
  select length( regexp_replace((select b from t), '[^,]+')) + 1 value_ from dual),
a_ as (
  select a from t),
b_ as (
  select regexp_substr( (select b from t), '[^,]', 1, level ) b,rownum rownum_
  from dual
  connect by level <= (select value_ from num_rows_)),
c_ as (
  select regexp_substr( (select c from t), '[^,]', 1, level ) c,rownum rownum_
  from dual
  connect by level <= (select value_ from num_rows_))  
select a_.a,b_.b,c_.c 
  from a_ 
  full outer join b_ on 1=1
  inner join c_ on b_.rownum_ = c_.rownum_;

http://sqlfiddle.com/#!4/f795b9/29

或更短,一步完成:

with a_ as
(select a from t),
b_c_ as (
  select regexp_substr( (select b from t), '[^,]', 1, level ) b,regexp_substr( (select c from t), '[^,]', 1, level ) c
  from dual
  connect by level <= (length( regexp_replace((select b from t), '[^,]+')) + 1)
)
select * from a_ cross join b_c_;

http://sqlfiddle.com/#!4/f795b9/32/0

【讨论】:

以上是关于UNNEST 多个值?的主要内容,如果未能解决你的问题,请参考以下文章

一次选择中的 Bigquery 多个 unnest

具有多个数组的 unnest 的 Jooq 表示法

Google Bigquery 外部加入 UNNEST

Bigquery unnest hits - 重复值)

BigQuery UNNEST 重复值

BigQuery:使用 UNNEST 检查数组的内容