基于一列SQL合并行

时间:2015-04-22 00:40:53

标签: sql oracle plsql oracle11g

我目前有user_addresses表:

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表中数据的新视图。 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表,因此用户只有一行,并且他们在自己的列中拥有主页/邮件地址。然后我从这个新的扁平视图中选择并做一个案例陈述:

case when mail_address is not null then mail_address else home_address end

我应该使用max(case when),工会/减号还是别的什么?实现这个目标的最佳方法是什么?

3 个答案:

答案 0 :(得分:1)

解决此问题的一种方法是使用“邮件”记录获取所有ID,然后将所有ID的所有“主”记录带到没有“邮件”记录的位置:

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;

答案 1 :(得分:1)

使用窗口函数:

 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;

答案 2 :(得分: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解析器输出:)