过滤提供的值否则返回所有内容

时间:2016-11-02 18:55:45

标签: sql

假设我有一个包含2列的表t

a int
b int

我可以进行如下查询:

select b
from t
where b > a
and a in(1,2,3)
order by b

其中1,2,3来自外部。

显然,查询不能返回任何行。在这种情况下,我想选择所有内容,就好像查询没有and a in(1,2,3)部分一样。也就是说,我喜欢:

if exists (
    select b
    from t
    where b > a
    and a in(1,2,3)
)
    select b
    from t
    where b > a
    and a in(1,2,3)
    order by b
else
    select b
    from t
    where b > a
    order by b

有没有办法做到这一点:

  • 不运行两个查询(一个用于存在,另一个用于实际查询)
  • 这比重复查询更简洁(真正的查询很长,所以DRY和所有这些东西)

2 个答案:

答案 0 :(得分:0)

使用带有子查询的NOT EXISTS来确定条件是否存在

SELECT b
FROM
    t
WHERE
    b > a
    AND (
       NOT EXISTS (SELECT 1 FROM @Table WHERE a IN (1,2,3))
       OR a IN (1,2,3)
    )
ORDER BY
    b

这是有效的原因是因为如果条件存在则OR语句将包含行,如果条件不存在则NOT EXISTS将包括所有行。

或使用公用表表达式和带有条件聚合的窗口函数。

WITH cte AS (
    SELECT
       b
       ,CASE WHEN a IN (1,2,3) THEN 1 ELSE 0 END as MeetsCondition
       ,COUNT(CASE WHEN a IN (1,2,3) THEN a END) OVER () as ConditionCount
    FROM
       t
)

SELECT
    b
FROM
    cte
WHERE
    (ConditionCount > 0 AND MeetsCondition = 1)
    OR (ConditionCount = 0)
ORDER BY
    b

答案 1 :(得分:-1)

我发现它有点"丑陋"。也许最好在临时表中实现查询的输出,然后根据临时表中的count执行第一次或第二次查询(这限制访问原始表3次到2次,你将能够为条件添加一些标志为您的条件不重复它)。除此之外,请阅读以下内容。 。

但是,请记住,EXISTS查询应该执行得非常快。它会停止是否找到满足条件的行。

您可以使用UNION ALL将约束查询的结果集与a列上没有约束的完整查询相结合,然后根据使用CASE语句的第一个查询的输出决定要显示的内容

CASE语句的工作原理:当找到查询的约束部分中的任何行时,从约束查询返回结果集,否则返回省略约束的所有内容。

如果您的数据库支持使用CTE,请使用此解决方案:

with tmp_data as (
select *
from ( 
  select 'constraint' as type, b
  from t
  where b > a 
    and a in (1,2,3) -- here goes your constraint
  union all
  select 'full query' as type, b
  from t
  where b > a
  ) foo
)
SELECT b
FROM tmp_data
WHERE 
  CASE WHEN (select count(*) from tmp_data where type = 'constraint') > 0 
    THEN type = 'constraint'
    ELSE type = 'full query' 
    END
;