I am trying to make a table off of another table. The original table has a row that looks like this:
------------------------
| col1 | col 2 | col 3 |
------------------------
| item | a,b,c | 1,2,3 |
------------------------
I'm trying to take that row, and put it into a table like this:
------------------------
| col1 | col 2 | col 3 |
------------------------
| item | a | 1 |
------------------------
| item | b | 2 |
------------------------
| item | c | 3 |
------------------------
So basically I am trying to UNNEST two comma separated rows at the same time. So far the best I have come up with is to UNNEST each column individually and then try to combine the two resulting tables (which I'm struggling with as well), but ideally I was hoping to do this in one step.
Here is my query to UNNEST one row at a time:
SELECT
col1, col2, col3
FROM
tableName,
UNNEST(SPLIT(col2)) AS col2
Here is my attempt at doing an UNNEST as a subquery, but it gives a ton of results:
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
The SQL standard allows to pass multiple values to the unnest()
function.
So the following should work (and does in 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)
That also deals correctly with different number of elements in the lists.
However, I don't know if your proprietary DBMS supports that.
Online example: http://rextester.com/XPN48947
by saying the original table has 'a row': do you mean exactly one? if yes, this does the trick:
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
or shorter, in one step:
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_;
You can use the unnest(split(col))
strategy, but don't cross-join both columns. Your answer implies an implicit order to the comma-separated values, so you'll need to establish a field ( RowNumber
below) to indicate this ordering.
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
I'm not sure how your rdbms handles effectively-null window partitioning. The above works in PostgreSQL. SQL Server would require order by (select null)
. Ymmv.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.