我有一个非常大的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' )))