SQL:有没有比“COALESCE on two selects”更好的方法来查找 OR 子句中的第一个非空结果?
Posted
技术标签:
【中文标题】SQL:有没有比“COALESCE on two selects”更好的方法来查找 OR 子句中的第一个非空结果?【英文标题】:SQL: Is there a better way than "COALESCE on two selects" to find the first non-null result in an OR clause? 【发布时间】:2021-12-07 12:46:29 【问题描述】:假设我有这张桌子:
ID | LANG | NAME | DEFAULT |
---|---|---|---|
1 | ENG | Cinderella | false |
1 | ENG | The Ash Bride | false |
1 | FRE | Cendrillon | true |
1 | GER | Aschenputtel | false |
(“灰烬新娘”纯属捏造,同一个ID可以有多个同种语言的名字) SQL 查询应返回所需语言的名称,如果不存在,则返回默认语言。
因此,如果用户的设置是德语 (GER),则查找图书应返回标题“Aschenputtel”,但如果用户设置为西班牙语 (SPA),则应返回“Cendrillon”。
This question 提出了同样的问题,但答案建议通过名称列表进行双重连接,一个用于“lang='[preferred]'”,一个用于默认值,COALESCE
用于查找第一个非空结果。我担心如果名称列表很长(超过 50,000 个条目),当没有主键(因为每种语言可以有很多名称)时,这会导致性能问题,而且问题很老,所以想知道是否有一种更类似于
SELECT NAME WHERE ID=1 and (LANG='SPA' OR DEFAULT=true)
并返回 OR 子句的第一个非空结果。理想情况下,类似于:
(not functional)
SELECT COALESCE(SELECT NAME WHERE ID=1 and (LANG='SPA' OR DEFAULT=true));
会回来
CENDRILLON
和
(not functional)
SELECT COALESCE(SELECT NAME WHERE ID=1 and (LANG='ENG' OR DEFAULT=true));
会回来
CINDERELLA
THE ASH BRIDE
有任何一种平滑的方法可以让一个 SQL 查询产生预期的结果,而无需对长列表进行双重连接?还是双重选择的合并是唯一的答案?
【问题讨论】:
样本数据很好,但您还需要指定预期结果。 我想我做到了?但我已经编辑了这个问题以进一步澄清这一点。 【参考方案1】:您可以通过某种方式对其进行排序,即 'SPA'
位于默认值(如果存在)之前,然后将结果限制为一条记录。
确切的语法取决于您使用的实际 DBMS。所以下面只是一个说明它的外观:
SELECT name
FROM elbat
WHERE lang = 'SPA'
OR default
ORDER BY CASE
WHEN lang = 'SPA' THEN
0
ELSE
1
END
LIMIT 1;
但我不知道这是否更有效。查看计划以获取相关信息。
【讨论】:
啊,太好了!当然!我从没想过在 ORDER BY 中使用 CASE。我目前正在使用 MariaDB,但我会尝试一下,看看它能带来什么。 嗯。当我在列表中有多个书名(不仅仅是 ID 1,还有更多,每个都有自己的标题列表)时,很难让这个工作。我想我必须以某种方式嵌套查询。 @Zimeon:根据您使用的 DBMS,您可以利用row_number()
窗口函数。如果您需要这方面的帮助,您可以发布一个新问题。但请确保您标记了您这次使用的 DBMS。并提供minimal reproducible example,即涉及的表或其他对象的CREATE
语句(粘贴文本,不要使用图像,不要链接到外部站点),INSERT
示例数据 (dito) 的语句以及表格文本格式的示例数据的所需结果。以上是关于SQL:有没有比“COALESCE on two selects”更好的方法来查找 OR 子句中的第一个非空结果?的主要内容,如果未能解决你的问题,请参考以下文章