基于一列合并行 SQL
Merge rows based on one column SQL
我目前有一个 user_addresses
table:
id | name | address_type | address
---+------+--------------+----------
1 | John | HOME | home addr
1 | John | MAIL | mail addr
2 | Bill | HOME | home addr
3 | Rick | HOME | home addr
3 | Rick | MAIL | mail addr
我想构建一个使用来自 user_addresses
table 的数据的新视图。当 address_type=MAIL
时,它应该在 address
字段中使用他们的邮件地址。否则它使用他们的 home
地址:
id | name | address_type | address | data from other tables
---+------+--------------+-----------+-----------------------
1 | John | MAIL | mail addr |
2 | Bill | HOME | home addr |
3 | Rick | MAIL | mail addr |
我目前正在将 user_addresses
table 展平,这样用户就排成一行,他们在自己的列中有 home/mail 个地址。然后我从这个新的平面视图中选择并做一个案例陈述:
case when mail_address is not null then mail_address else home_address end
我应该使用 max(case when)
、union/minus 还是其他?完成此任务的最佳方法是什么?
解决这个问题的一种方法是获取所有带有 "mail" 记录的 ID,然后获取所有没有 "mail" 记录的所有 ID 的 "home" 记录:
select ua.*
from user_addresses us
where address_type = 'MAIL'
union all
select ua.*
from user_addresses ua
where address_type = 'HOME' and
not exists (select 1
from user_addresses ua2
where ua2.id = ua.id and ua2.address_type = 'MAIL'
);
另一种方法是使用 row_number()
:
对行进行优先排序
select ua.*
from (select ua.*,
row_number() over (partition by id order by (case when address_type = 'MAIL' then 1 else 2 end)) as seqnum
from user_addresses ua
) ua
where seqnum = 1;
使用window 功能:
create or replace view v
as
with cte as
(
select id , name , address_type , address,
row_number() over(partition by id order by address_type desc) rn
from your_table
)
select id , name , address_type , address from cte where rn=1;
有什么不使用 PIVOT 的特殊原因吗?
Oracle 11g R2 架构设置:
CREATE TABLE t
("id" int, "name" varchar2(4), "address_type" varchar2(4), "address" varchar2(9))
;
INSERT ALL
INTO t ("id", "name", "address_type", "address")
VALUES (1, 'John', 'HOME', 'home addr')
INTO t ("id", "name", "address_type", "address")
VALUES (1, 'John', 'MAIL', 'mail addr')
INTO t ("id", "name", "address_type", "address")
VALUES (2, 'Bill', 'HOME', 'home addr')
INTO t ("id", "name", "address_type", "address")
VALUES (3, 'Rick', 'HOME', 'home addr')
INTO t ("id", "name", "address_type", "address")
VALUES (3, 'Rick', 'MAIL', 'mail addr')
SELECT * FROM dual
;
查询 1:
with flat as (
select * from t
pivot(
max("address")
for "address_type" in ('HOME' as home,'MAIL' as mail)
)
)
select "id","name",coalesce(mail, home) as address
from flat
| id | name | ADDRESS |
|----|------|-----------|
| 2 | Bill | home addr |
| 3 | Rick | mail addr |
| 1 | John | mail addr |
p.s。忽略双引号标识符 - 懒得修复 sqlfiddle 的 text-to-ddl 解析器输出:)
我目前有一个 user_addresses
table:
id | name | address_type | address
---+------+--------------+----------
1 | John | HOME | home addr
1 | John | MAIL | mail addr
2 | Bill | HOME | home addr
3 | Rick | HOME | home addr
3 | Rick | MAIL | mail addr
我想构建一个使用来自 user_addresses
table 的数据的新视图。当 address_type=MAIL
时,它应该在 address
字段中使用他们的邮件地址。否则它使用他们的 home
地址:
id | name | address_type | address | data from other tables
---+------+--------------+-----------+-----------------------
1 | John | MAIL | mail addr |
2 | Bill | HOME | home addr |
3 | Rick | MAIL | mail addr |
我目前正在将 user_addresses
table 展平,这样用户就排成一行,他们在自己的列中有 home/mail 个地址。然后我从这个新的平面视图中选择并做一个案例陈述:
case when mail_address is not null then mail_address else home_address end
我应该使用 max(case when)
、union/minus 还是其他?完成此任务的最佳方法是什么?
解决这个问题的一种方法是获取所有带有 "mail" 记录的 ID,然后获取所有没有 "mail" 记录的所有 ID 的 "home" 记录:
select ua.*
from user_addresses us
where address_type = 'MAIL'
union all
select ua.*
from user_addresses ua
where address_type = 'HOME' and
not exists (select 1
from user_addresses ua2
where ua2.id = ua.id and ua2.address_type = 'MAIL'
);
另一种方法是使用 row_number()
:
select ua.*
from (select ua.*,
row_number() over (partition by id order by (case when address_type = 'MAIL' then 1 else 2 end)) as seqnum
from user_addresses ua
) ua
where seqnum = 1;
使用window 功能:
create or replace view v
as
with cte as
(
select id , name , address_type , address,
row_number() over(partition by id order by address_type desc) rn
from your_table
)
select id , name , address_type , address from cte where rn=1;
有什么不使用 PIVOT 的特殊原因吗?
Oracle 11g R2 架构设置:
CREATE TABLE t
("id" int, "name" varchar2(4), "address_type" varchar2(4), "address" varchar2(9))
;
INSERT ALL
INTO t ("id", "name", "address_type", "address")
VALUES (1, 'John', 'HOME', 'home addr')
INTO t ("id", "name", "address_type", "address")
VALUES (1, 'John', 'MAIL', 'mail addr')
INTO t ("id", "name", "address_type", "address")
VALUES (2, 'Bill', 'HOME', 'home addr')
INTO t ("id", "name", "address_type", "address")
VALUES (3, 'Rick', 'HOME', 'home addr')
INTO t ("id", "name", "address_type", "address")
VALUES (3, 'Rick', 'MAIL', 'mail addr')
SELECT * FROM dual
;
查询 1:
with flat as (
select * from t
pivot(
max("address")
for "address_type" in ('HOME' as home,'MAIL' as mail)
)
)
select "id","name",coalesce(mail, home) as address
from flat
| id | name | ADDRESS |
|----|------|-----------|
| 2 | Bill | home addr |
| 3 | Rick | mail addr |
| 1 | John | mail addr |
p.s。忽略双引号标识符 - 懒得修复 sqlfiddle 的 text-to-ddl 解析器输出:)