SQL进阶--EXISTS谓词的用法

SQL谓词指的是返回真值的函数
EXISTS与其他谓词不同,接受的参数是集合
因此EXISTS可以看出一种高阶的函数
SQL中没有与全称量词相当的谓词,可以使用not exists代替

1、存在量化

-- 建表
create table meetings(
    meeting varchar(10),
    person  varchar(10)
);
insert into meetings values ('第一次', '伊藤');
insert into meetings values ('第一次', '水岛');
insert into meetings values ('第一次', '坂东');
insert into meetings values ('第二次', '伊藤');
insert into meetings values ('第二次', '宫田');
insert into meetings values ('第三次', '坂东');
insert into meetings values ('第三次', '水岛');
insert into meetings values ('第三次', '宫田');

求缺席者

-- 存在量化的应用
select DISTINCT m1.meeting, m2.person
  from meetings m1 cross join meetings m2 
 where not EXISTS   
      (select *
         from meetings m3 
        where m1.meeting = m3.meeting
          and m2.person = m3.person)
;

-- 使用差集运算
select m1.meeting , m2.person
  from meetings m1,meetings m2 
minus
select meeting, person
  from meetings
;

结果(oracle)

MEETING    PERSON
---------- ----------
第二次     水岛
第二次     坂东
第三次     伊藤
第一次     宫田

2、全称量化

用双重否定

-- 创表
create table testscores(
    student_id INTEGER,
    subject1    varchar(10),
    score       INTEGER
);
insert into testscores values(100, '数学', 100);
insert into testscores values(100, '语文', 80);
insert into testscores values(100, '理化', 80);
insert into testscores values(200, '数学', 80);
insert into testscores values(200, '语文', 95);
insert into testscores values(300, '数学', 40);
insert into testscores values(300, '语文', 90);
insert into testscores values(300, '社会', 55);
insert into testscores values(400, '数学', 80);

数学分数在80分以上及语文分数在50分以上的学生

select distinct a.student_id
  from testscores a 
 where a.subject1 in ('数学', '语文')
   and not EXISTS
      (select * 
         from testscores b
        where b.student_id = a.student_id
          and 1 = case when b.subject1 = '数学' and b.score < 80 then 1
                       when b.subject1 = '语文' and b.score < 50 then 1
                  else 0 end )
 group by a.student_id
having count(*) >= 2
;

结果(oracle)

STUDENT_ID
----------
       100
       200

3、集合和谓词比较

-- 创表
drop table projects_1_8;
create table projects_1_8(
    project_id varchar(10),
    step_nbr   INTEGER,
    status1    varchar(10)
)
;

insert into projects_1_8 values('AA100', 0, '完成');
insert into projects_1_8 values('AA100', 1, '等待');
insert into projects_1_8 values('AA100', 2, '等待');
insert into projects_1_8 values('B200', 0, '等待');
insert into projects_1_8 values('B200', 1, '等待');
insert into projects_1_8 values('CS300', 0, '完成');
insert into projects_1_8 values('CS300', 1, '完成');
insert into projects_1_8 values('CS300', 2, '等待');
insert into projects_1_8 values('CS300', 3, '等待');
insert into projects_1_8 values('DY400', 0, '完成');
insert into projects_1_8 values('DY400', 1, '完成');
insert into projects_1_8 values('DY400', 2, '完成');

查询完成到了工程1的项目
面向集合的解法

select project_id
  from projects_1_8
 group by project_id
having count(*) = sum(case when step_nbr <= 1 and status1 = '完成' then 1
                           when step_nbr >= 2 and status1 = '等待' then 1
                           else 0 end)
;

面向集合的解法——结果(oracle)

PROJECT_ID
----------
CS300

谓语逻辑的解法


-- 谓语逻辑的解法 (双重否定)
select * 
  from projects_1_8 A
 where not EXISTS
      (select status1
         from projects_1_8 b
        where a.project_id = b.project_id -- 以项目为单位进行条件判断
          and status1 <> case when step_nbr <= 1 then '完成'
                         else '等待' end)
;

谓语逻辑的解法——结果(oracle)

PROJECT_ID   STEP_NBR STATUS1
---------- ---------- ----------
CS300               3 等待
CS300               2 等待
CS300               1 完成
CS300               0 完成

4、集合和谓词的优缺点

谓词的优点

1、性能好,只要有一行满足条件就停止,不一定需要查询所有行的数据
2、结果中包含的信息量大。如果用having 会被聚合

谓词的缺点

1、使用了双重否定不容易被理解

>

内容多来自 《SQL进阶教材》,仅做笔记。

猜你喜欢

转载自blog.csdn.net/scc_hy/article/details/80644512