SQL:单个人存在多个地址。如果存在则选择当前地址,否则选择永久地址

Posted

技术标签:

【中文标题】SQL:单个人存在多个地址。如果存在则选择当前地址,否则选择永久地址【英文标题】:SQL: Multiple addresses present for single person. Select current address if present otherwise select permanent address 【发布时间】: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

谢谢!

【问题讨论】:

【参考方案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;

【讨论】:

以上是关于SQL:单个人存在多个地址。如果存在则选择当前地址,否则选择永久地址的主要内容,如果未能解决你的问题,请参考以下文章

t-sql 如果记录存在则选择一列,如果不存在则选择不同的列

os常用讲解

SQL - 如果 OLEQuery 中存在,则选择列

SQL:如果存在,则限制用户。如果不存在,则显示所有内容

Azure 策略:如果所有者标签不存在或不是电子邮件地址,则拒绝

MS SQL 2008/Access 2002 VBA - 检查数据库的当前记录,如果不存在则输入