【问题标题】:SQL: Multiple addresses present for single person. Select current address if present otherwise select permanent addressSQL:单个人存在多个地址。如果存在则选择当前地址,否则选择永久地址
【发布时间】:2021-03-16 13:06:26
【问题描述】:

我有这种情况,如果有人有当前地址,则需要选择该地址,否则选择永久地址。

我不想将Address 表与Person 加入两次,因为这会影响性能。

| person_id | name  | surname
+-----------+-------+----------
| 10        | ABC10 | XYZ10
| 11        | ABC11 | XYZ11
| 12        | ABC12 | XYZ12
| 13        | ABC13 | XYZ13

地址

| ID    | person_id | type      | address   | city
+-------+-----------+-----------+-----------+----------
| 1     | 10        | Permanent | addr 10P  | city 10P
| 2     | 10        | Current   | addr 10C  | city 10C
| 3     | 11        | Permanent | addr 11P  | city 11P
| 4     | 12        | Permanent | addr 12P  | city 12P
| 5     | 12        | Current   | addr 12C  | city 12C
| 6     | 13        | Permanent | addr 13P  | city 13P 

预期输出:

| person_id | name  | surname   | type      | address   | city
+-----------+-------+-----------+-----------+-----------+-----------
| 10        | ABC10 | XYZ10     | Current   | addr 10C  | city 10C
| 11        | ABC11 | XYZ11     | Permanent | addr 11P  | city 11P
| 12        | ABC12 | XYZ12     | Current   | addr 12C  | city 12C
| 13        | ABC13 | XYZ13     | Permanent | addr 13P  | city 13P

谢谢!

【问题讨论】:

    标签: sql oracle inner-join query-optimization greatest-n-per-group


    【解决方案1】:

    一个选项使用横向连接和 fetch 子句:

    select p.*, a.type, a.address, a.city
    from person p
    cross apply (
        select a.*
        from address a
        where a.person_id = p.person_id
        order by case a.type when 'Current' then 1 else 2 end
        fetch first row only
    ) a
    

    您还可以使用窗口函数(这适用于所有 Oracle 版本):

    select p.*, a.type, a.address, a.city
    from person p
    inner join (
        select a.*, 
            row_number() over(partition by person_id order by case type when 'Current' then 1 else 2 end) as rn
        from address a
    ) a on a.person_id = p.person_id
    where a.rn = 1
    

    case 表达式可以轻松地使用更多可能的地址类型扩展优先级逻辑。如果您只有两个值,“Permanent”和“Current”,那么可以在两个查询中将其简化为:order by type(这会将“Current”放在首位)。

    【讨论】:

      【解决方案2】:

      您可以使用窗口函数来解决这个问题:

      select p.*, a.type, a.address, a.city
      from person p join
           (select a.*,
                   row_number() over (partition by a.person_id order by a.type) as seqnum
            from address a
           ) a
           on a.person_id = p.person_id and a.seqnum = 1;
      

      注意:这里假设类型只有“当前”和“永久”,所以它使用字符串排序来选择“当前”。

      【讨论】:

        【解决方案3】:

        您可以根据需要使用row_numberrankdense_rank函数。

        使用row_number的方法如下:

        select * from
        (select p.*, a.type, a.address, a.city,
                row_number() over (partition by a.person_id order by a.type) as rn
           from person p join address a
             on a.person_id = p.person_id
        ) where rn = 1;
        

        【讨论】:

          猜你喜欢
          • 2014-11-24
          • 2020-09-30
          • 1970-01-01
          • 2011-11-01
          • 2011-08-01
          • 2021-12-19
          • 2018-07-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多