LEFT JOIN:有没有办法减少行号?

时间:2015-09-02 13:47:40

标签: mysql sql left-join

我开发的软件允许用户管理他们想要出售的房产。我有一个像这样的数据库(简单例子):

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

返回类似的内容:

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个请求更快)。

但这只是一个简单的例子。在真正的数据库中,我有很多其他要加载的表,里面有很多值。如此多的表,相同类型的请求只返回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

3 个答案:

答案 0 :(得分:2)

它有点复杂,它使用变量,但答案是“是”:

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;

这会为给定属性的照片和文档添加枚举值。然后汇总这些。

答案 1 :(得分:1)

您甚至可以通过简单的聚合将每个属性减少到一行。

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;

答案 2 :(得分:0)

我会这样做:

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