SQL查询where子句如果没有匹配记录则省略

Posted

技术标签:

【中文标题】SQL查询where子句如果没有匹配记录则省略【英文标题】:SQL Query where clause omit if no matching records 【发布时间】:2020-12-04 04:09:58 【问题描述】:

我目前正在处理一个从具有 20 列的复杂 sql 视图中读取数据的 sql 查询。 我应该使用 8 where 条件读取数据。在这 8 个条件中,有一个条件是可选的。意思是,如果没有满足所有这 8 个条件的匹配记录,则省略可选的 where 条件并返回结果。

下面是一个进一步解释的例子::

表格:: EMPLOYEE_DETAILS

EMP_NO  EMP_NAME    EMP_DEPT_NO     PREF_LANGUAGE       LOCATION
------  --------    -----------     -------------       ---------
1       Name1       101             ENGLISH             USA
2       Name2       102             SPANISH             SPAIN
3       Name3       103             ENGLISH             USA 
4       Name4       102             ITALIAN             ITALY
5       Name5       103             ENGLISH             USA
6       Name6       103             ITALIAN             ITALY

查询:

SELECT * FROM EMPLOYEE_DETAILS
    WHERE EMP_DEPT_NO = 103 AND LOCATION ='USA' AND PREF_LANGUAGE = 'SPANISH'

在此示例 sql 查询中,PREF_LANGUAGE 条件是可选的。 如果有匹配所有三个条件的记录,则只返回那些匹配的记录。 由于上表没有满足所有三个条件的记录,因此查询应省略可选条件(即 PREF_LANGUAGE),并返回满足其余两个必需条件的记录。

非常感谢任何帮助。

谢谢

【问题讨论】:

【参考方案1】:

我想我会像这样对查询进行调整:

WITH cte AS (
      SELECT ed.*,
             SUM(CASE WHEN PREF_LANGUAGE = 'SPANISH' THEN 1 ELSE 0 END) OVER () as NUM_PREF_SPANISH
      FROM EMPLOYEE_DETAILS ed
      WHERE EMP_DEPT_NO = 103 AND LOCATION = 'USA'
     )

SELECT *
FROM cte
WHERE PREF_LANGUAGE = 'SPANISH' OR
      NUM_PREF_LANGUAGE = 0;

这样表述的原因是 Oracle 并不总是实现 CTE。这保证了 CTE 仅被引用一次,因此优化器不会决定多次运行您的复杂代码。

您也可以使用WITH TIES 技巧在最新版本的 Oracle 中执行此操作:

SELECT ed.*,                 
FROM EMPLOYEE_DETAILS ed
WHERE EMP_DEPT_NO = 103 AND LOCATION = 'USA'
ORDER BY(CASE WHEN PREF_LANGUAGE = 'SPANISH' THEN 1 ELSE 2 END)
FETCH FIRST 1 ROW WITH TIES;

【讨论】:

【参考方案2】:

我会在这里使用存在逻辑:

WITH cte AS (
    SELECT *
    FROM EMPLOYEE_DETAILS
    WHERE
        EMP_DEPT_NO = 103 AND
        LOCATION = 'USA'
)

SELECT *
FROM cte
WHERE PREF_LANGUAGE = 'SPANISH' OR
      NOT EXISTS (SELECT 1 FROM cte
                  WHERE PREF_LANGUAGE = 'SPANISH')

在简单的英语中,上述查询将返回部门为 103、位置为美国以及首选语言为西班牙语的记录没有记录具有此首选语言。在后一种情况下,无论首选语言如何,它都会返回记录。

【讨论】:

谢谢蒂姆,但我提到的那个查询是一个例子。我目前在生产中工作的 sql 查询比我在示例中显示的要大得多。您的建议使我的 sql 查询更加难看,因为我必须复制/粘贴几乎整个 30 行 sql 查询。请提出仅适用于该可选 where 条件的内容。【参考方案3】:

你可以使用DENSE_RANK解析函数如下:

SELECT * FROM 
(SELECT T.*,  
        DENSE_RANK() 
          OVER (ORDER BY CASE WHEN PREF_LANGUAGE = 'SPANISH' THEN 1 ELSE 2 END) AS RN
  FROM EMPLOYEE_DETAILS T
 WHERE EMP_DEPT_NO = 103 
   AND LOCATION ='USA')
WHERE RN = 1

【讨论】:

以上是关于SQL查询where子句如果没有匹配记录则省略的主要内容,如果未能解决你的问题,请参考以下文章

如果记录存在则添加 WHERE 子句

SQL severa 中l数据库如何进行查询

如果查询结果在 BigQuery 中没有记录,则显示默认值

如何在 SQL 查询中动态跳过没有 If else 的 where 子句?

SQL 删除

SSIS 查找行为很奇怪