基于一列合并行 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 的特殊原因吗?

SQL Fiddle

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

Results:

| id | name |   ADDRESS |
|----|------|-----------|
|  2 | Bill | home addr |
|  3 | Rick | mail addr |
|  1 | John | mail addr |

p.s。忽略双引号标识符 - 懒得修复 sqlfiddle 的 text-to-ddl 解析器输出:)