使用一个选择查询代替查询+子查询

时间:2019-10-28 19:42:10

标签: sql sql-server

SQL Server 2014中,数据已更改为保护数据。我希望以下内容有意义。

我必须在表格中搜索具有中等风险的所有类别。然后,我需要进入另一个表(测试)并检索那些只有Toby测试失败的“中等”类别。在第一个表中类别是唯一的。

因此,在下面的示例数据中,类别4和5均为中等风险,并且在测试表中都具有Toby且结果为“失败”。

但是我想从最终输出中排除类别4,因为该类别的Bill测试也失败了。

我的目标只是将第5类显示为输出。我可以使用查询和子查询来执行此操作,其中子查询返回类别4和5,并在其上进行主查询过滤。但是我可以通过一个查询以某种方式实现同​​一件事吗?

更新:

我当前的查询如下。对于这篇文章,我不得不稍作修改,我希望它足够了。基本上,子查询会提取对中级类别进行任何测试失败的所有类别,而主查询会过滤掉其他失败的类别。

select tt.category, tt.[name]
from test_table mt
where tt.category in (select mt.category
                      from main_table mt
                      inner join test_table tt on tt.category = mt.category
                      where mt.risk= 'Moderate' and tt.result = 'Fail')
  and tt.[name] <> 'Toby'
  and tt.[result] = 'Fail'

输出:

category    risk
----------------------
1           Minimal
2           Critical
3           Elevated
4           Moderate
5           Moderate


category    name    result
-------------------------------
1           Mark    Pass
1           Bill    No Result
1           John    Pass
1           Toby    Pass

2           Mark    Pass
2           Bill    No Result
2           John    Fail
2           Toby    Pass

3           Mark    Pass
3           Bill    No Result
3           John    Pass
3           Toby    Pass

4           Mark    Pass
4           Bill    Fail
4           John    Pass
4           Toby    Fail

5           Mark    Pass
5           Bill    Pass
5           John    Pass
5           Toby    Fail

2 个答案:

答案 0 :(得分:2)

加入表group by category并在HAVING子句中设置条件:

select c.category
from categories c inner join test t
on c.category = t.category
where c.risk = 'Moderate'
group by c.category
having 
  sum(case when t.name = 'Toby' and t.result = 'Fail' then 1 else 0 end) > 0
  and 
  sum(case when t.name <> 'Toby' and t.result = 'Fail' then 1 else 0 end) = 0

或:

select c.category
from categories c inner join test t
on c.category = t.category
where c.risk = 'Moderate' and t.result = 'Fail'
group by c.category
having count(distinct t.name) = 1 and max(t.name) = 'Toby'

请参见demo
结果:

> | category |
> | -------: |
> |        5 |

答案 1 :(得分:0)

直接阅读您的问题提示exists / not exists

select c.*
from categories c
where c.risk = 'Moderate' and
      exists (select 1
              from tests t
              where t.category = c.category and
                    t.name = 'Toby' and
                    t.result = 'Fail'
             ) and
      not exists (select 1
                  from tests t
                  where t.category = c.category and
                        t.name <> 'Toby' and
                        t.result = 'Fail'
                 );

有条件聚合也是可行的解决方案,当过滤器仅位于一个表上时,我更喜欢这种解决方案。但是,这里的过滤是在两个表上进行的,这将在test(category, result, name)上使用索引,并避免外部聚集。