我经常发现自己在桌子上进行了几次独立的连接.例如,假设我们有桌子collections,有独立的与两个一对N的关系photos和songs,其中N是从零到很多.
现在,假设我们希望得到一个集合,这两个公司(独立)相关联的照片和歌曲.
我通常会使用这样的东西:
SELECT
collections.collectionid as collectionid,
photos.name as photo_name,
songs.name as song_name
FROM collections
LEFT JOIN photos ON collections.collectionid = photos.collectionid
LEFT JOIN songs ON collections.collectionid = songs.collectionid
WHERE collections.collectionid = 14
Run Code Online (Sandbox Code Playgroud)
当然,将一个表左连接到另外两个表,如果第一个连接导致M行而第二个连接N成行,则给M * N出行.就数据库流量和性能而言,这似乎不是最理想的.
+--------------+------------+-----------+
| collectionid | photo_name | song_name |
+--------------+------------+-----------+
| 14 | 'x' | 'a' | \
| 14 | 'x' | 'b' | - Each photo is returned 3 times,
| 14 | 'x' | 'c' | / because 3 songs are returned.
| 14 | 'y' | 'a' | \
| 14 | 'y' | 'b' |
| 14 | 'y' | 'c' | /
+--------------+------------+-----------+
Run Code Online (Sandbox Code Playgroud)
或者,您可以执行两个选择:两个单独的查询,每个查询连接collections到不同的表,给M + N出行:
SELECT
collections.collectionid as collectionid
song.name as song_name
FROM collections
LEFT JOIN songs on collections.collectionid = songs.collectionid
WHERE collections.collectionid = 14
Run Code Online (Sandbox Code Playgroud)
和:
SELECT
collections.collectionid as collectionid
photos.name as photo_name
FROM collections
LEFT JOIN photos on collections.collectionid = photos.collectionid
WHERE collections.collectionid = 14
Run Code Online (Sandbox Code Playgroud)
赠送:
+--------------+------------+ +--------------+------------+
| collectionid | song_name | | collectionid | photo_name |
+--------------+------------+ +--------------+------------+
| 14 | 'a' | | 14 | 'x' |
| 14 | 'b' | | 14 | 'y' |
| 14 | 'c' | +--------------+------------+
+--------------+------------+
Run Code Online (Sandbox Code Playgroud)
我的问题:处理这个问题的最佳方法是什么?
上述两者似乎都不是最佳的.那么,是否存在导致M + N行的另一种方式,但是可以在单个查询中完成?
您的第一个选项(两个独立的JOIN)似乎没有为您提供非常有用的结果集(因为这两个子表生成半笛卡尔积,您必须在应用程序代码中重复删除结果).
第二个选项(两个单独的查询)是可以的,除非您想将两个查询的结果视为单个集合用于表示目的(例如,通过日期字段将它们一起排序).
我认为,最好的解决方案是将两个查询合并为一个UNION ALL,生成一个只包含您实际需要的行的结果集:
SELECT
collections.collectionid as collectionid,
photos.name as photo_name,
'photo' as document_type
FROM collections
LEFT JOIN photos on collections.collectionid = photos.collectionid
WHERE collections.collectionid = 14
UNION ALL
SELECT
collections.collectionid as collectionid,
song.name as photo_name
'song' as document_type
FROM collections
LEFT JOIN songs on collections.collectionid = songs.collectionid
WHERE collections.collectionid = 14
Run Code Online (Sandbox Code Playgroud)
这种结果集可以是ORDERed BY整个组合记录集中的任何字段,允许(例如)获取附加到集合的20个最新文档,而不管它们是什么类型.