我有表Building
和Address
,其中每个Building
与0..n Addresses
相关联。
我想列出Buildings
与关联的Address
。如果Building
有几个入口,因此有几个Addresses
,我不关心显示哪一个。{1}}。如果Building
没有已知地址,则地址字段应为null
。
这就是,我希望像左连接一样最多连接一行。
如何在Oracle SQL中表达这一点?
PS:我的查询将包括对两个表的相关限制。因此,我想避免在查询文本中重复这些限制。
答案 0 :(得分:4)
我会考虑查询SELECT子句中的地址,例如:
SELECT b.*
,(SELECT a.text
FROM addresses a
WHERE a.buildingid = b.id
AND ROWNUM=1) as atext
FROM building b;
ROWNUM=1
表示“只要有一个,不关心哪个”。
这种方法的优点是,只要在addresses.buildingid上存在合适的索引,它就可能比大多数替代方案表现更好。一旦为每个查询的建筑物找到一个地址,它就会停止寻找更多的地址。
这种方法的缺点是如果你想要地址表中的多个列,你不能 - 尽管你可以将它们连接成一个字符串。
答案 1 :(得分:2)
因为您不关心显示多个地址中的哪一个:
Oracle 9i +:
WITH summary AS (
SELECT b.*,
a.*,
ROW_NUMBER() OVER (PARTITION BY b.building_id) rn
FROM BUILDINGS b
LEFT JOIN ADDRESSES a ON a.building_id = b.building_id)
SELECT s.*
FROM summary s
WHERE s.rn = 1
非子查询因子等价:
SELECT s.*
FROM (SELECT b.*,
a.*,
ROW_NUMBER() OVER (PARTITION BY b.building_id) rn
FROM BUILDINGS b
LEFT JOIN ADDRESSES a ON a.building_id = b.building_id) s
WHERE s.rn = 1
答案 2 :(得分:0)
您可以做的是对您加入的地址数据的限制。 例如,要求没有地址较低的地址:
select *
from building b
left join addresses a on (a.buildingid = b.id)
where not exists (select 1 from addresses a2
where a2.buildingid = b.id and a2.id < a.id)
在这种情况下,每栋建筑最多可获得1个地址。
答案 3 :(得分:0)
select b.*, max(a.id) as aid
from building b
left outer join addresses a on (a.buildingid = b.id)
group by a.buildingid
或
select b.*, maxid
from building b
left outer join
(
select buildingid, max(id) as maxid
from addresses
group by buildingid
) a on (a.buildingid = b.id)
答案 4 :(得分:0)
梅里,
此方法使用嵌套的内联视图。我已经在大型数据集上证明了这种方法,它表现得非常好。
理解查询的最佳方法是从最内层的“M”内联视图开始。为了调试和清晰,我添加了计数。这标识了每个建筑物的最大(即最近的???)地址ID:
select maxa.b_id, max(maxa.a_id) a_id, count(*) c
from address maxa
group by maxa.b_id;
下一个“A”内联视图使用上面的“M”内联视图来决定获取哪个地址,然后加入该地址id以返回一组地址字段:
select ma.b_id, ma.a_id, ma.addr1, ma.addr2, ma.addr3, m.c
from address ma,
( select maxa.b_id, max(maxa.a_id) a_id, count(*) c
from address maxa
group by maxa.b_id ) m
where ma.a_id = m.a_id;
上面的“A”内联视图为最终查询提供了一组转换后的地址。虽然BUILDING和ADDRESS之间的关系是1到0..n,但BUILDING和“A”之间的关系是1到0..1,一个基本的外连接:
select b.b_id, b.b_code, b.b_name, a.*
from building b,
( select ma.b_id, ma.a_id, ma.addr1, ma.addr2, ma.addr3, m.c
from address ma,
( select maxa.b_id, max(maxa.a_id) a_id, count(*) c
from address maxa
group by maxa.b_id ) m
where ma.a_id = m.a_id ) a
where b.b_id = a.b_id (+);
这种方法的主要优点是:
create view latest_address (b_id, a_id, addr1, addr2, addr3, c) as select ma.b_id, ma.a_id, ma.addr1, ma.addr2, ma.addr3, m.c from address ma, ( select maxa.b_id, max(maxa.a_id) a_id, count(*) c from address maxa group by maxa.b_id ) m where ma.a_id = m.a_id; select b.b_id, b.b_code, b.b_name, a.* from building b, latest_address a where b.b_id = a.b_id (+);
享受!
马修