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

时间:2013-09-06 13:16:48

标签: php sql if-statement switch-statement case

我有一个非常大的MySQL语句循环通过php foreach和每个循环连接到前一个与union all。我会将语句简化为我的问题的核心,如果需要,我当然也可以根据要求添加更多细节。

我有这张桌子

+--------+-----------+-----------+
|   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

Sitenote我可能不会使用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'))

5 个答案:

答案 0 :(得分:1)

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

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'

这将为您提供所有标有“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))

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

答案 1 :(得分:0)

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'

答案 2 :(得分:0)

您可以在这样的问题中得到确切的结果:

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

请参阅Fiddle-example

如果你真的想每次都能提供身份证件

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

每个ID(Fiddle-example)仅提供一个结果。

您还可以使用多个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)并执行select。 请参阅Fiddle-example

答案 3 :(得分:0)

更好地了解mysql中的case语句

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

更好地了解mysql中的if语句

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

答案 4 :(得分:-1)

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