SQL IF ELSE / CASE 子句在 WHERE 条件中


SQL IF ELSE / CASE clause in WHERE condition

我有一个非常大的MySQL语句,它通过php foreach循环,每个循环都连接到前一个。我将简化陈述到我问题的核心,如果需要,我当然也可以稍后根据要求添加更多详细信息。

我有这张桌子

+--------+-----------+-----------+
|   ID   |   LANG    |   TITLE   |
+--------+-----------+-----------+
|   1    |    EN     |   T-A     |
+--------+-----------+-----------+
|   1    |    FR     |   T-A     |
+--------+-----------+-----------+
|   2    |    FR     |   T-B     |
+--------+-----------+-----------+
|   3    |    DE     |   T-C     |
+--------+-----------+-----------+
|   3    |    EN     |   T-C     |
+--------+-----------+-----------+

我想在 SQL SELECT 中编写一个 WHERE 条件,该条件应该为每个 ID 显示最多一个结果。但仅当 LANG 为 FR 或 EN时,它才应显示结果。在顶部应首选 FR,并且仅当 ID 没有可用的 FR 时,才应将 EN 显示为替代。所以结果看起来像这样。

+--------+-----------+-----------+
|   ID   |   LANG    |   TITLE   |
+--------+-----------+-----------+
|   1    |    FR     |   T-A     |
+--------+-----------+-----------+
|   2    |    FR     |   T-B     |
+--------+-----------+-----------+
|   3    |    EN     |   T-C     |
+--------+-----------+-----------+

我尝试自己使用 If - else/case 构建一些东西,但我对 SQL 不是很有经验,所以任何帮助都会得到很多赞赏。

我尝试的简化 SQL 类似于

SELECT * FROM `table` 
WHERE `table`.`ID` = 1
IF `table`.`LANG` = 'FR' 
BEGIN
  AND `table`.`LANG` = 'FR' 
END
ELSE
BEGIN
  AND `table`.`LANG` = 'EN' 
END
union all 
SELECT * FROM `table` 
WHERE `table`.`ID` = 2
IF `table`.`LANG` = 'FR' 
BEGIN
  AND `table`.`LANG` = 'FR' 
END
ELSE
BEGIN
  AND `table`.`LANG` = 'EN' 
END
union all 
SELECT * FROM `table` 
WHERE `table`.`ID` = 3
IF `table`.`LANG` = 'FR' 
BEGIN
  AND `table`.`LANG` = 'FR' 
END
ELSE
BEGIN
  AND `table`.`LANG` = 'EN' 
END

站点注释 我可能不会使用任何将 ORDER BY 与 LIMIT 1 结合使用的构造,因为我通过 php 多次循环 SQL。

编辑:对我有用的解决方案

SELECT * FROM `table1`
WHERE ID = 1
AND lang = 'FR'
OR (lang = 'EN' AND ID NOT IN (SELECT ID FROM table1 WHERE lang = 'FR'))

使用复杂的查询优化器的最优雅和最有效的解决方案是:

SELECT * FROM (
    SELECT * FROM `table`
    WHERE ID IN (
      SELECT id FROM `table` 
      WHERE lang = 'EN'
      EXCEPT
      SELECT id FROM `table`
      WHERE lang = 'FR'
    ) OR table.LANG ='FR'
) t1
WHERE id = ?

这将为您提供所需的结果,按 ID 过滤。但是,如果优化器无法降低id = ?则可能需要自己完成才能获得不错的性能:

  SELECT * FROM `table`
    WHERE id = ? AND (ID IN (
      SELECT id FROM `table` 
      WHERE lang = 'EN' AND ID = ?
      EXCEPT
      SELECT id FROM `table`
      WHERE lang = 'FR' AND ID = ?
    ) OR table.LANG ='FR')

但是,如果可以的话,我会立即获得所有结果,而不是首先迭代 ID:

SELECT * FROM `table`
WHERE ID IN (
  SELECT id FROM `table` 
  WHERE lang = 'EN'
  EXCEPT
  SELECT id FROM `table`
  WHERE lang = 'FR'
) OR table.LANG ='FR'

这将为您提供所有具有lang"EN"且没有相应"FR"以及所有"FR"的ID。或者,您也可以尝试:

SELECT * FROM `table`
WHERE lang = 'FR'
OR (lang = 'EN' AND ID NOT IN (SELECT ID FROM table WHERE lang = 'FR'))

SELECT * FROM `table`
WHERE lang = 'FR'
OR (table.LANG = 'EN' AND NOT EXISTS (SELECT * FROM table t1 WHERE lang = 'FR' AND t1.id = table.id))

但我的猜测是第一个查询是最快的。

select * from table where lang = 'FR' union
select t_en.* from table t_en left join table t_fr 
on (t_fr.id = t_en.id and t_fr.lang = 'FR' and t_en.lang = 'EN')
where t_fr.id is null and t_en.lang = 'EN'

您可以在您的问题中获得确切的结果,如下所示:

SELECT * FROM `table`
WHERE lang = 'FR'
OR (lang = 'EN' AND ID NOT IN (SELECT ID FROM `table` WHERE lang = 'FR'))

参见小提琴示例

如果你真的想每次都给身份证,你可以做

SELECT * FROM `table`
WHERE (ID=1) AND
( lang = 'FR'
  OR (lang = 'EN' AND ID NOT IN (SELECT ID FROM `table` WHERE lang = 'FR'))
)

这只为每个 ID 提供一个结果(小提琴示例)。

您也可以使用多个 ID

SELECT * FROM `table`
WHERE (ID in (1,2,3)) AND
( lang = 'FR'
  OR (lang = 'EN' AND ID NOT IN (SELECT ID FROM `table` WHERE lang = 'FR'))
)

并从脚本构建(1,2,3)并执行选择。参见小提琴示例。

以便更好地了解MySQL中的案例陈述

http://dev.mysql.com/doc/refman/5.0/en/case.html

为了更好地了解 MySQL 中的 if 语句

http://dev.mysql.com/doc/refman/5.0/en/if.html
SELECT * FROM TABLE WHERE ( LANG='FR' OR (lang='EN' AND ID NOT IN (SELECT ID FROM TABLE WHERE lang='FR' )))