LEFT JOIN :有没有办法减少行号?
LEFT JOIN : is there a way to reduce the line numbers?
我在开发一款软件,允许用户管理他们想要出售的房产。我有一个这样的数据库(简单的例子):
estates
-------------
id
price
photos
-------------
photoName
estateId
documents
-------------
docName
estateId
我想在一次请求中获得一处房产(假设 id = 1)的所有信息、它的照片和它的文件,所以我做了类似的事情:
SELECT * FROM estates
LEFT OUTER JOIN photos ON photos.estateId = id
LEFT OUTER JOIN documents ON documents.estateId = id
WHERE id = 1
哪个 returns 像 :
id | price | photoName | estateId | docName
----------------------------------------------
1 | 10000 | photo1.jpg| 1 | doc1.pdf
1 | 10000 | photo1.jpg| 1 | doc2.pdf
1 | 10000 | photo1.jpg| 1 | doc3.pdf
1 | 10000 | photo2.jpg| 1 | doc1.pdf
1 | 10000 | photo2.jpg| 1 | doc2.pdf
1 | 10000 | photo2.jpg| 1 | doc3.pdf
(assuming estate n°1 has 2 photos and 3 docs for the exemple)
然后,使用一些 PHP 脚本,我遍历结果以仅获得唯一结果,就是这样,我只用一个请求加载了我的资产(这比启动 3 个请求更快)。
但这只是一个简单的例子。在真实数据库中,我有很多其他表需要加载,里面有很多值。如此多的表格,同一类型的请求 returns 超过 2,000,000 行,仅用于一个庄园。信不信由你,加载时间很长 ^^'。
所以我想知道是否有某种神奇的东西可以给我这样的结果:
id | price | photoName | estateId | docName
----------------------------------------------
1 | 10000 | photo1.jpg| 1 | doc1.pdf
1 | 10000 | photo2.jpg| 1 | doc2.pdf
1 | 10000 | NULL* | 1 | doc3.pdf
*NULL or whatever you want, I don't care.
所以请求返回的行数是具有最多值的列的行数(在示例中,文档比照片多,因此行数与文档一样多)。
有这样的东西吗?
~ MetalFox Dioxymore
有点复杂,而且使用了变量,但是答案是"yes":
select e.*,
max(photoname) as photoname, max(docname) as docname)
from estates e join
((select p.estateid, p.photoname, NULL as docname, (@rnp := @rnp + 1) as seqnum
from photos p cross join
(select @rnp := 0) params
where p.estateid = 1
) union all
(select d.estateid, NULL, d.docname, (@rnd := @rnd + 1) as seqnum
from documents d cross join
(select @rnd := 0) params
where d.estateid = 1
)
) dp
on dp.estateid = e.estateid
group by e.stateid, dp.seqnum
order by e.stateid, dp.seqnum;
这会为给定遗产的照片和文件添加一个枚举值。然后汇总这些。
我会这样做:
SELECT e.id, p.photoName FROM Estates e
LEFT JOIN Photos p on p.estateId = e.id
WHERE e.id = 1
UNION ALL
SELECT e.id, d.docName FROM Estates e
LEFT JOIN Documents d on d.estateId = e.id
WHERE e.id = 1
请参阅此处使用 SQLFiddle:http://sqlfiddle.com/#!9/79ce2/7
您甚至可以通过简单聚合将其减少到每个庄园一行。
SELECT
e.*,
group_concat(distinct p.photoname) as photonames,
group_concat(distinct d.docname) as docnames
FROM estates e
LEFT OUTER JOIN photos p ON p.estateId = e.id
LEFT OUTER JOIN documents d ON d.estateId = e.id
WHERE e.id = 1
GROUP BY e.id;
这会为您提供 'photo1.jpg,photo2.jpg'
和 'doc1.pdf,doc2.pdf,doc3.pdf'
等字符串。使用 PHP 的 explode
函数从字符串中获取数组。
关于性能:由于将所有照片与所有文档等结合在一起,以上会产生一个很大的中间结果集。因此使用子查询可能会更快。并且不再需要使用 DISTINCT - 一个很好的指标,可以更直接地检索数据。
SELECT
e.*,
(select group_concat(p.photoname) from photos p where p.estateId = e.id) as photonames,
(select group_concat(d.docname) from documents d where d.estateId = e.id) as docnames
FROM estates e
WHERE e.id = 1;
再说一句:对于很多照片和文档或大文件名,您可能需要扩展 GROUP_CONCAT 的最大允许长度:
SET SESSION group_concat_max_len = 10000;
我在开发一款软件,允许用户管理他们想要出售的房产。我有一个这样的数据库(简单的例子):
estates
-------------
id
price
photos
-------------
photoName
estateId
documents
-------------
docName
estateId
我想在一次请求中获得一处房产(假设 id = 1)的所有信息、它的照片和它的文件,所以我做了类似的事情:
SELECT * FROM estates
LEFT OUTER JOIN photos ON photos.estateId = id
LEFT OUTER JOIN documents ON documents.estateId = id
WHERE id = 1
哪个 returns 像 :
id | price | photoName | estateId | docName
----------------------------------------------
1 | 10000 | photo1.jpg| 1 | doc1.pdf
1 | 10000 | photo1.jpg| 1 | doc2.pdf
1 | 10000 | photo1.jpg| 1 | doc3.pdf
1 | 10000 | photo2.jpg| 1 | doc1.pdf
1 | 10000 | photo2.jpg| 1 | doc2.pdf
1 | 10000 | photo2.jpg| 1 | doc3.pdf
(assuming estate n°1 has 2 photos and 3 docs for the exemple)
然后,使用一些 PHP 脚本,我遍历结果以仅获得唯一结果,就是这样,我只用一个请求加载了我的资产(这比启动 3 个请求更快)。
但这只是一个简单的例子。在真实数据库中,我有很多其他表需要加载,里面有很多值。如此多的表格,同一类型的请求 returns 超过 2,000,000 行,仅用于一个庄园。信不信由你,加载时间很长 ^^'。
所以我想知道是否有某种神奇的东西可以给我这样的结果:
id | price | photoName | estateId | docName
----------------------------------------------
1 | 10000 | photo1.jpg| 1 | doc1.pdf
1 | 10000 | photo2.jpg| 1 | doc2.pdf
1 | 10000 | NULL* | 1 | doc3.pdf
*NULL or whatever you want, I don't care.
所以请求返回的行数是具有最多值的列的行数(在示例中,文档比照片多,因此行数与文档一样多)。
有这样的东西吗?
~ MetalFox Dioxymore
有点复杂,而且使用了变量,但是答案是"yes":
select e.*,
max(photoname) as photoname, max(docname) as docname)
from estates e join
((select p.estateid, p.photoname, NULL as docname, (@rnp := @rnp + 1) as seqnum
from photos p cross join
(select @rnp := 0) params
where p.estateid = 1
) union all
(select d.estateid, NULL, d.docname, (@rnd := @rnd + 1) as seqnum
from documents d cross join
(select @rnd := 0) params
where d.estateid = 1
)
) dp
on dp.estateid = e.estateid
group by e.stateid, dp.seqnum
order by e.stateid, dp.seqnum;
这会为给定遗产的照片和文件添加一个枚举值。然后汇总这些。
我会这样做:
SELECT e.id, p.photoName FROM Estates e
LEFT JOIN Photos p on p.estateId = e.id
WHERE e.id = 1
UNION ALL
SELECT e.id, d.docName FROM Estates e
LEFT JOIN Documents d on d.estateId = e.id
WHERE e.id = 1
请参阅此处使用 SQLFiddle:http://sqlfiddle.com/#!9/79ce2/7
您甚至可以通过简单聚合将其减少到每个庄园一行。
SELECT
e.*,
group_concat(distinct p.photoname) as photonames,
group_concat(distinct d.docname) as docnames
FROM estates e
LEFT OUTER JOIN photos p ON p.estateId = e.id
LEFT OUTER JOIN documents d ON d.estateId = e.id
WHERE e.id = 1
GROUP BY e.id;
这会为您提供 'photo1.jpg,photo2.jpg'
和 'doc1.pdf,doc2.pdf,doc3.pdf'
等字符串。使用 PHP 的 explode
函数从字符串中获取数组。
关于性能:由于将所有照片与所有文档等结合在一起,以上会产生一个很大的中间结果集。因此使用子查询可能会更快。并且不再需要使用 DISTINCT - 一个很好的指标,可以更直接地检索数据。
SELECT
e.*,
(select group_concat(p.photoname) from photos p where p.estateId = e.id) as photonames,
(select group_concat(d.docname) from documents d where d.estateId = e.id) as docnames
FROM estates e
WHERE e.id = 1;
再说一句:对于很多照片和文档或大文件名,您可能需要扩展 GROUP_CONCAT 的最大允许长度:
SET SESSION group_concat_max_len = 10000;