我正在动态地构建一个SELECT语句,该语句将提取一个项目以及可能包含多个相关项目的列表。
最终目标是在应用程序空间中的一个对象,其中包含每个相关类型的ID数组。
使用JOIN列表非常简单:
SELECT items.*, item_has_related1.related1_id, item_has_related2.related2_id, ...
FROM (items)
LEFT JOIN item_has_related1 ON item_has_related1.item_id = items.id
LEFT JOIN item_has_related2 ON item_has_related2.item_id = items.id
... potentially many more
WHERE items.id = $itemId;
使用 LEFT JOIN
是因为某些关系可能为空。
最明显的问题是,返回的行数是所有联接中匹配数的乘积。仅使用几个联接表,该数目可能会很大。如果有五个表,每个表有六个匹配项,那么将有6 ^ 5行!第二个问题是,处理返回行更加复杂,因为我必须在每一列中挖掘出唯一的值。
作为替代方案,我写了类似这样的内容,它基本上对每个JOIN进行单独的查询:
SELECT items.*, item_has_related_1.related1_id, NULL as related2_id, ...
FROM (items)
JOIN item_has_related_1 ON item_has_related_1.item_id = items.id
WHERE items.id = $itemId
UNION
SELECT items.*, NULL as related1_id, item_has_related_2.related2_id, ...
FROM (items)
JOIN item_has_related_2 ON item_has_related_2.item_id = items.id
WHERE items.id = $itemId
以这种方式返回的行数是所有联接中的匹配数之和。但是,查询准备时间要长得多,因此对于较小的数据集,此方法效率较低。我试图凭经验确定“较小”的定义,但是根据测试数据,我不确定结果是否有意义。
是否有更有效的方法来执行多个JOIN并合并结果,还是有另一种方法可以解决此问题?
编辑后添加: Barmar对我的问题有正确的答案,但是我的下一步是扩展where子句以返回多行。提到this question,我的代码最终看起来像这样:
SELECT items.*,
(SELECT GROUP_CONCAT(related1_id) FROM item_has_related_1 WHERE item_id = items.id) as related1Ids,
(SELECT GROUP_CONCAT(related2_id) FROM item_has_related_2 WHERE item_id = items.id) as related2Ids,
...
FROM items
WHERE <where criteria>
答案 0 :(得分:1)
您可以使用GROUP_CONCAT
将每个表中的所有相关项目放入结果中以逗号分隔的列表中。
SELECT items.*, related1_ids, related2_ids, ...
FROM items
LEFT JOIN (
SELECT item_id, GROUP_CONCAT(related1_id) AS related1_ids
FROM item_has_related_1
WHERE item_id = $itemId
) AS r1 ON items.id = r1.item_id
LEFT JOIN (
SELECT item_id, GROUP_CONCAT(related2_id) AS related2_ids
FROM item_has_related_2
WHERE item_id = $itemId
) AS r2 ON items.id = r2.item_id
...
稍后您可以使用应用程序语言对其进行拆分。
答案 1 :(得分:0)
您可以像这样简单地使用内部联接编写查询:
SELECT items.*, item_has_related1.related1_id, item_has_related2.related2_id, ...
FROM (items)
INNER JOIN item_has_related1 ON item_has_related1.item_id = items.id
INNER JOIN item_has_related2 ON item_has_related2.item_id = items.id
... potentially many more
WHERE items.id = $itemId;
此查询的行数与其他表中$itemId
的匹配项相同。
问题是,如果您将需要select语句中列出的所有那些数据,则您将必须进行连接所有查询的工作,即使它们是分开的,也无法通过使用所有方法获得任何收益如此处列出的那样加入。