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 可以使用不同的索引来优化资源利用。

  • 以更长的代码为代价