MySQL 要使用的条件
MySQL Conditional For Which Join to use
在查询中,是否可以有条件地选择要使用的连接?在下面的查询中,m.bodyNo
有时是空的,而连接使用 m.chassisNo
来显示数据,我希望它显示具有值的结果。
SELECT m.`seriesYear`, m.`bodyNo`, m.`modelDesc`
FROM parts_parsed p
LEFT JOIN parts_modelno m ON p.`modelNo` = m.`bodyNo`
WHERE p.`partNo` = '$PartNos'
尝试两个连接会在我的查询测试器 (HeidiSQL) 中显示所有数据,它为两个连接的相关列提供相同的名称,但需要为每个值提供别名并在 PHP 所以我正在寻找更直接的东西。也许像 COALESCE 这样的东西可以做到,但不确定如何应用它。谁能建议如何进行?
SELECT m1.`seriesYear`, m1.`bodyNo`, m1.`modelDesc`, m2.`seriesYear`, m2.`bodyNo`, m2.`modelDesc`
FROM parts_parsed p
LEFT JOIN parts_modelno m1 ON p.`modelNo` = m1.`chassisNo`
LEFT JOIN parts_modelno m2 ON p.`bodyNo` = m2.`bodyNo`
WHERE p.`partNo` = '$PartNos'
如果这没有丢失格式,它是 parse_parts:
的示例
ID pageNo baseGroup partID partNo modelNo bodyNo isRHD
1 1 0 1 391906 2201 0
2 1 0 1 391906 2202 0
3 1 0 1 391906 2211 0
4 1 0 1 391906 2220 0
5 1 0 1 391906 2222 0
43493 315 30 9983 386405 2250 0
43494 315 30 9983 386405 2251 0
43495 315 30 9983 386405 2270 0
43496 315 30 9983 386405 2271 0
43497 315 30 9984 438463 2650 0
这是 parts_modelno
的样本
ID seriesYear bodyNo chassisNo engineNo modelDesc
1 1948-49 2213 2213 G600000 HEARSE AND AMBULANCE
2 1948-49 2250 2226 G600000 7 PASS, CUSTOM EIGHT LIMOUSINE
3 1948-49 2251 2226 G600000 7 PASS, CUSTOM EIGHT SEDAN
4 1948-49 2252 2206 G600000 6 PASS, CUSTOM EIGHT SEDAN
5 1948-49 2255 2206 G600000 6 PASS, CUSTOM EIGHT CLUB SEDAN
6 1948-49 2259 2233 G600000 6 PASS, CUSTOM EIGHT CONVERTIBLE VICTORIA
7 1948-49 2262 2211 G200000 6 PASS, DELUXE EIGHT TOURING SEDAN
8 1948-49 2265 2211 G200000 6 PASS, DELUXE EIGHT CLUB SEDAN
9 1948-49 2270 2222 G400000 7 PASS, DELUXE SUPER EIGHT LIMOUSINE
10 1948-49 2271 2222 G400000 7 PASS, DELUXE SUPER EIGHT SEDAN
parts_modelno 在 bodyNo 和 chassisNo 列的所有行中都有完全填充的值,而 parts_parts 有 bodyNo 或 modelNo 两者都有,但在少数情况下,这两个值是相同。 parts_modelno.chassisNo 匹配 parts_parsed.modelNo.
您可以使用这样的案例方法..
SELECT m1.`seriesYear`,
m1.`bodyNo`,
m1.`modelDesc`,
m2.`seriesYear`,
m2.`bodyNo`,
m2.`modelDesc`
CASE
WHEN m2.value <> "" THEN m2.value
ELSE m1.value
END AS someName
FROM parts_parsed p
LEFT JOIN parts_modelno m1 ON p.`modelNo` = m1.`chassisNo`
LEFT JOIN parts_modelno m2 ON p.`modelNo` = m2.`bodyNo`
WHERE p.`partNo` = '$PartNos'
为什么不直接使用 coalesce
进行连接?
LEFT JOIN parts_modelno m ON p.modelNo = coalesce(m.bodyNo, m.chassisNo)
可能还有其他更好的答案,但这行得通。
SELECT COALESCE(m1.`seriesYear`, m2.`seriesYear`) AS seriesYear,
COALESCE(m1.`modelDesc`, m2.`modelDesc`) AS modelDesc,
COALESCE(m1.`bodyNo`, m2.`chassisNo`) AS bodyNo
FROM parts_parsed p
LEFT JOIN parts_modelno m1 ON p.`modelNo` = m1.`chassisNo`
LEFT JOIN parts_modelno m2 ON p.`bodyNo` = m2.`bodyNo`
WHERE p.`partNo` = '$PartNos'
在各种评论中你说你并不真正关心性能,在这种情况下你只想要最简单和最可维护的代码?
所以,只需在连接谓词中使用 OR
即可?
SELECT
p.`baseGroup`,
m.`seriesYear`,
m.`modelDesc`,
m.`bodyNo`,
m.`chassisNo` AS modelNo
FROM
parts_parsed p
LEFT JOIN
parts_modelno m
ON p.`bodyNo` = m.`bodyNo`
OR p.`modelNo` = m.`chassisNo`
WHERE
p.`partNo` = '$PartNos'
这假设 p
永远不会同时填充 bodyNo
和 modelNo
。如果可能的话,您需要用您想要的行为示例来更新问题。
如其他地方所述,此代码还意味着索引可以不能用于优化查询计划。
编辑:
如果性能确实很重要 (而且它应该,即使你只指 cpu 和磁盘利用率而不是用户体验),你应该简单地 UNION
两个查询。这允许优化器充分利用索引来避免无意义的读取,选择更好的连接实现等。
SELECT
*
FROM
(
SELECT
p.`baseGroup`,
p.`partNo`,
m.`seriesYear`,
m.`modelDesc`,
m.`bodyNo`,
m.`chassisNo` AS modelNo
FROM
parts_parsed p
INNER JOIN
parts_modelno m
ON p.`bodyNo` = m.`bodyNo`
UNION ALL
SELECT
p.`baseGroup`,
p.`partNo`,
m.`seriesYear`,
m.`modelDesc`,
m.`bodyNo`,
m.`chassisNo` AS modelNo
FROM
parts_parsed p
INNER JOIN
parts_modelno m
ON p.`modelNo` = m.`chassisNo`
)
part_list
WHERE
`partNo` = '$PartNos'
UNION ALL
优于 UNION
,因为后者避免了 UNION
的重复数据删除开销。
最终结果是只有一个或其他 sub-query 将包含任何给定部分的任何结果,并且每个 sub-query 可以使用不同的索引来优化资源利用。
- 以更长的代码为代价
在查询中,是否可以有条件地选择要使用的连接?在下面的查询中,m.bodyNo
有时是空的,而连接使用 m.chassisNo
来显示数据,我希望它显示具有值的结果。
SELECT m.`seriesYear`, m.`bodyNo`, m.`modelDesc`
FROM parts_parsed p
LEFT JOIN parts_modelno m ON p.`modelNo` = m.`bodyNo`
WHERE p.`partNo` = '$PartNos'
尝试两个连接会在我的查询测试器 (HeidiSQL) 中显示所有数据,它为两个连接的相关列提供相同的名称,但需要为每个值提供别名并在 PHP 所以我正在寻找更直接的东西。也许像 COALESCE 这样的东西可以做到,但不确定如何应用它。谁能建议如何进行?
SELECT m1.`seriesYear`, m1.`bodyNo`, m1.`modelDesc`, m2.`seriesYear`, m2.`bodyNo`, m2.`modelDesc`
FROM parts_parsed p
LEFT JOIN parts_modelno m1 ON p.`modelNo` = m1.`chassisNo`
LEFT JOIN parts_modelno m2 ON p.`bodyNo` = m2.`bodyNo`
WHERE p.`partNo` = '$PartNos'
如果这没有丢失格式,它是 parse_parts:
的示例ID pageNo baseGroup partID partNo modelNo bodyNo isRHD
1 1 0 1 391906 2201 0
2 1 0 1 391906 2202 0
3 1 0 1 391906 2211 0
4 1 0 1 391906 2220 0
5 1 0 1 391906 2222 0
43493 315 30 9983 386405 2250 0
43494 315 30 9983 386405 2251 0
43495 315 30 9983 386405 2270 0
43496 315 30 9983 386405 2271 0
43497 315 30 9984 438463 2650 0
这是 parts_modelno
的样本ID seriesYear bodyNo chassisNo engineNo modelDesc
1 1948-49 2213 2213 G600000 HEARSE AND AMBULANCE
2 1948-49 2250 2226 G600000 7 PASS, CUSTOM EIGHT LIMOUSINE
3 1948-49 2251 2226 G600000 7 PASS, CUSTOM EIGHT SEDAN
4 1948-49 2252 2206 G600000 6 PASS, CUSTOM EIGHT SEDAN
5 1948-49 2255 2206 G600000 6 PASS, CUSTOM EIGHT CLUB SEDAN
6 1948-49 2259 2233 G600000 6 PASS, CUSTOM EIGHT CONVERTIBLE VICTORIA
7 1948-49 2262 2211 G200000 6 PASS, DELUXE EIGHT TOURING SEDAN
8 1948-49 2265 2211 G200000 6 PASS, DELUXE EIGHT CLUB SEDAN
9 1948-49 2270 2222 G400000 7 PASS, DELUXE SUPER EIGHT LIMOUSINE
10 1948-49 2271 2222 G400000 7 PASS, DELUXE SUPER EIGHT SEDAN
parts_modelno 在 bodyNo 和 chassisNo 列的所有行中都有完全填充的值,而 parts_parts 有 bodyNo 或 modelNo 两者都有,但在少数情况下,这两个值是相同。 parts_modelno.chassisNo 匹配 parts_parsed.modelNo.
您可以使用这样的案例方法..
SELECT m1.`seriesYear`,
m1.`bodyNo`,
m1.`modelDesc`,
m2.`seriesYear`,
m2.`bodyNo`,
m2.`modelDesc`
CASE
WHEN m2.value <> "" THEN m2.value
ELSE m1.value
END AS someName
FROM parts_parsed p
LEFT JOIN parts_modelno m1 ON p.`modelNo` = m1.`chassisNo`
LEFT JOIN parts_modelno m2 ON p.`modelNo` = m2.`bodyNo`
WHERE p.`partNo` = '$PartNos'
为什么不直接使用 coalesce
进行连接?
LEFT JOIN parts_modelno m ON p.modelNo = coalesce(m.bodyNo, m.chassisNo)
可能还有其他更好的答案,但这行得通。
SELECT COALESCE(m1.`seriesYear`, m2.`seriesYear`) AS seriesYear,
COALESCE(m1.`modelDesc`, m2.`modelDesc`) AS modelDesc,
COALESCE(m1.`bodyNo`, m2.`chassisNo`) AS bodyNo
FROM parts_parsed p
LEFT JOIN parts_modelno m1 ON p.`modelNo` = m1.`chassisNo`
LEFT JOIN parts_modelno m2 ON p.`bodyNo` = m2.`bodyNo`
WHERE p.`partNo` = '$PartNos'
在各种评论中你说你并不真正关心性能,在这种情况下你只想要最简单和最可维护的代码?
所以,只需在连接谓词中使用 OR
即可?
SELECT
p.`baseGroup`,
m.`seriesYear`,
m.`modelDesc`,
m.`bodyNo`,
m.`chassisNo` AS modelNo
FROM
parts_parsed p
LEFT JOIN
parts_modelno m
ON p.`bodyNo` = m.`bodyNo`
OR p.`modelNo` = m.`chassisNo`
WHERE
p.`partNo` = '$PartNos'
这假设 p
永远不会同时填充 bodyNo
和 modelNo
。如果可能的话,您需要用您想要的行为示例来更新问题。
如其他地方所述,此代码还意味着索引可以不能用于优化查询计划。
编辑:
如果性能确实很重要 (而且它应该,即使你只指 cpu 和磁盘利用率而不是用户体验),你应该简单地 UNION
两个查询。这允许优化器充分利用索引来避免无意义的读取,选择更好的连接实现等。
SELECT
*
FROM
(
SELECT
p.`baseGroup`,
p.`partNo`,
m.`seriesYear`,
m.`modelDesc`,
m.`bodyNo`,
m.`chassisNo` AS modelNo
FROM
parts_parsed p
INNER JOIN
parts_modelno m
ON p.`bodyNo` = m.`bodyNo`
UNION ALL
SELECT
p.`baseGroup`,
p.`partNo`,
m.`seriesYear`,
m.`modelDesc`,
m.`bodyNo`,
m.`chassisNo` AS modelNo
FROM
parts_parsed p
INNER JOIN
parts_modelno m
ON p.`modelNo` = m.`chassisNo`
)
part_list
WHERE
`partNo` = '$PartNos'
UNION ALL
优于 UNION
,因为后者避免了 UNION
的重复数据删除开销。
最终结果是只有一个或其他 sub-query 将包含任何给定部分的任何结果,并且每个 sub-query 可以使用不同的索引来优化资源利用。
- 以更长的代码为代价