【问题标题】:Merge rows based on one column SQL基于一列 SQL 合并行
【发布时间】:2015-04-22 00:40:53
【问题描述】:

我目前有一个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)、联合/减号还是其他什么?完成此任务的最佳方法是什么?

【问题讨论】:

  • 当你尝试这些时发生了什么?

标签: sql oracle plsql oracle11g


【解决方案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 |

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

【讨论】:

    【解决方案2】:

    解决此问题的一种方法是获取所有带有“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;
    

    【讨论】:

      【解决方案3】:

      使用窗口函数:

       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;
      

      【讨论】:

        猜你喜欢
        • 2021-12-02
        • 2020-05-31
        • 1970-01-01
        • 2019-03-19
        • 2022-01-25
        • 2018-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多