如何使用 Left Join 和子查询修复 SQL 查询?
How to fix SQL query with Left Join and subquery?
我有 SQL 使用 LEFT JOIN 的查询:
SELECT COUNT(stn.stocksId) AS count_stocks
FROM MedicalFacilities AS a
LEFT JOIN stocks stn ON
(stn.stocksIdMF = ( SELECT b.MedicalFacilitiesIdUser
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY stn.stocksId DESC LIMIT 1)
AND stn.stocksEndDate >= UNIX_TIMESTAMP() AND stn.stocksStartDate <= UNIX_TIMESTAMP())
这些查询我想 select 从 table stocks
的一行按条件和字段等于 a.MedicalFacilitiesIdUser
.
我总是得到 count_stocks = 0
结果。但是我需要得到 1
count(...)
聚合不计算 null
,因此它的参数很重要:
COUNT(stn.stocksId)
因为 stn
是你的右手 table,如果 left join
未命中,这将不算数。您可以使用:
COUNT(*)
计算每一行,即使它的所有列都是 null
。或者左边的列 table (a
) 永远不会 null
:
COUNT(a.ID)
你在 on
中的子查询对我来说很奇怪:
on stn.stocksIdMF = ( SELECT b.MedicalFacilitiesIdUser
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY stn.stocksId DESC LIMIT 1)
这是比较 MedicalFacilitiesIdUser
和 stocksIdMF
。诚然,您没有示例数据或数据布局,但列的命名表明它们不是同一回事。也许你打算:
on stn.stocksIdMF = ( SELECT b.stocksId
-----------------------------^
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY b.stocksId DESC
LIMIT 1)
此外,按 stn.stocksid
排序不会做任何有用的事情,因为那将来自 外部 子查询。
您的子查询似乎多余,而且主查询难以阅读,因为大部分连接语句都可以放在 where 子句中。此外,原始查询可能存在性能问题。
回想一下 WHERE
是隐式连接,JOIN
是显式连接。查询优化器
如果它们使用相同的表达式,则两者之间没有区别,但可读性和可维护性是另一回事。
考虑修改版本(注意我加了一个GROUP BY
):
SELECT COUNT(stn.stocksId) AS count_stocks
FROM MedicalFacilities AS a
LEFT JOIN stocks stn ON stn.stocksIdMF = a.MedicalFacilitiesIdUser
WHERE stn.stocksEndDate >= UNIX_TIMESTAMP()
AND stn.stocksStartDate <= UNIX_TIMESTAMP()
GROUP BY stn.stocksId
ORDER BY stn.stocksId DESC
LIMIT 1
我有 SQL 使用 LEFT JOIN 的查询:
SELECT COUNT(stn.stocksId) AS count_stocks
FROM MedicalFacilities AS a
LEFT JOIN stocks stn ON
(stn.stocksIdMF = ( SELECT b.MedicalFacilitiesIdUser
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY stn.stocksId DESC LIMIT 1)
AND stn.stocksEndDate >= UNIX_TIMESTAMP() AND stn.stocksStartDate <= UNIX_TIMESTAMP())
这些查询我想 select 从 table stocks
的一行按条件和字段等于 a.MedicalFacilitiesIdUser
.
我总是得到 count_stocks = 0
结果。但是我需要得到 1
count(...)
聚合不计算 null
,因此它的参数很重要:
COUNT(stn.stocksId)
因为 stn
是你的右手 table,如果 left join
未命中,这将不算数。您可以使用:
COUNT(*)
计算每一行,即使它的所有列都是 null
。或者左边的列 table (a
) 永远不会 null
:
COUNT(a.ID)
你在 on
中的子查询对我来说很奇怪:
on stn.stocksIdMF = ( SELECT b.MedicalFacilitiesIdUser
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY stn.stocksId DESC LIMIT 1)
这是比较 MedicalFacilitiesIdUser
和 stocksIdMF
。诚然,您没有示例数据或数据布局,但列的命名表明它们不是同一回事。也许你打算:
on stn.stocksIdMF = ( SELECT b.stocksId
-----------------------------^
FROM medicalfacilities AS b
WHERE b.MedicalFacilitiesIdUser = a.MedicalFacilitiesIdUser
ORDER BY b.stocksId DESC
LIMIT 1)
此外,按 stn.stocksid
排序不会做任何有用的事情,因为那将来自 外部 子查询。
您的子查询似乎多余,而且主查询难以阅读,因为大部分连接语句都可以放在 where 子句中。此外,原始查询可能存在性能问题。
回想一下 WHERE
是隐式连接,JOIN
是显式连接。查询优化器
如果它们使用相同的表达式,则两者之间没有区别,但可读性和可维护性是另一回事。
考虑修改版本(注意我加了一个GROUP BY
):
SELECT COUNT(stn.stocksId) AS count_stocks
FROM MedicalFacilities AS a
LEFT JOIN stocks stn ON stn.stocksIdMF = a.MedicalFacilitiesIdUser
WHERE stn.stocksEndDate >= UNIX_TIMESTAMP()
AND stn.stocksStartDate <= UNIX_TIMESTAMP()
GROUP BY stn.stocksId
ORDER BY stn.stocksId DESC
LIMIT 1