sql 语句的查询结果

yyouyou 2018-10-15 04:12:09
有3张表
学生表student
Sno Sname
201215121 李勇
201215122 刘晨
201215123 王敏
201215126 杨天
201215125 张立

课程表course
Cno Cname
1 数据库
2 数学
3 信息系统
4 操作系统
5 数据结构
6 数据处理
7 PASCAL语言

选修成绩表SC

Sno Cno Grade
201215121 1 92
201215121 2 85
201215121 3 88
201215122 2 90
201215122 3 80
201215126 1 80
201215126 2 70
201215126 3 60
201215126 4 85
201215126 5 89
201215126 6 90
201215126 7 94

现在我想查找哪些选了全部的课程,用exists实现
select sname
from student
where exists
(select *
from sc
where student.sno=sc.sno
group by sc.sno
having count(cno)=7)
结果是正确的,就是:杨天
但是,如果我用 not exists,就不对了。我的SQL代码如下
select sname
from student
where not exists
(select SC.sno
from sc
where Student.Sno=sc.sno
group by SC.sno
having count(cno)!=7)

结果为
sname
王敏
张立
杨天

没搞懂啊,两个否定应该是一样的效果啊
相关子查询,带入应该也没问题啊
求教!谢谢了!
...全文
280 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
吉普赛的歌 版主 2018-10-16
  • 打赏
  • 举报
回复
引用 7 楼 yyouyou 的回复:
谢谢你了,因为开始那个不正确的语句和这个正确语句就是在子查询中相差在select的属性上及用了group by,所以一直搞不懂怎么回事。 按照你的方法,那就是在子查询中,select *方式和select sno ,数据的查询方式还是有区别。 select * 就是把父查询的每条记录带入子查询,select sno 这样带有属性的就是与父查询的表进行左外连接。不知道我这样理解对不对?
不是。 #6 的那种写法, 如果光那个子查询, 根本行不通。 not exists 大部分能转化成 left join , #6 正好是个特例而已。 不必在这种小细节上纠结了, 能用就行了吧。
yyouyou 2018-10-16
  • 打赏
  • 举报
回复
好的,谢谢你了。非常感谢。
引用 8 楼 yenange 的回复:
[quote=引用 7 楼 yyouyou 的回复:]
谢谢你了,因为开始那个不正确的语句和这个正确语句就是在子查询中相差在select的属性上及用了group by,所以一直搞不懂怎么回事。
按照你的方法,那就是在子查询中,select *方式和select sno ,数据的查询方式还是有区别。
select * 就是把父查询的每条记录带入子查询,select sno 这样带有属性的就是与父查询的表进行左外连接。不知道我这样理解对不对?


不是。
#6 的那种写法, 如果光那个子查询, 根本行不通。
not exists 大部分能转化成 left join , #6 正好是个特例而已。

不必在这种小细节上纠结了, 能用就行了吧。
[/quote]
yyouyou 2018-10-15
  • 打赏
  • 举报
回复
引用 6 楼 yenange 的回复:
[quote=引用 5 楼 yyouyou 的回复:]
谢谢你,我先去试一试。
不好意思,#2漏了一行,#2的写法是

select sname
from student
where not exists
(select *
from sc
where Student.Sno=sc.sno

having count(cno)!=7)


这个没办法转化了, 不过也不难理解:
每一个 sno 拿出来在子查询中统计, 不存在总数为 7 的就去掉。[/quote]

谢谢你了,因为开始那个不正确的语句和这个正确语句就是在子查询中相差在select的属性上及用了group by,所以一直搞不懂怎么回事。
按照你的方法,那就是在子查询中,select *方式和select sno ,数据的查询方式还是有区别。
select * 就是把父查询的每条记录带入子查询,select sno 这样带有属性的就是与父查询的表进行左外连接。不知道我这样理解对不对?
吉普赛的歌 版主 2018-10-15
  • 打赏
  • 举报
回复
引用 5 楼 yyouyou 的回复:
谢谢你,我先去试一试。 不好意思,#2漏了一行,#2的写法是 select sname from student where not exists (select * from sc where Student.Sno=sc.sno having count(cno)!=7)
这个没办法转化了, 不过也不难理解: 每一个 sno 拿出来在子查询中统计, 不存在总数为 7 的就去掉。
yyouyou 2018-10-15
  • 打赏
  • 举报
回复
谢谢你,我先去试一试。
不好意思,#2漏了一行,#2的写法是

select sname
from student
where not exists
(select *
from sc
where Student.Sno=sc.sno

having count(cno)!=7)

引用 4 楼 yenange 的回复:
改成等价写法, 就很容易理解了:

USE tempdb
GO
IF OBJECT_ID('student') IS NOT NULL DROP TABLE student
GO
CREATE TABLE student(
sno VARCHAR(20),
sname NVARCHAR(10)
)
GO
INSERT INTO student
SELECT 201215121,N'李勇'
UNION ALL SELECT 201215122,N'刘晨'
UNION ALL SELECT 201215123,N'王敏'
UNION ALL SELECT 201215126,N'杨天'
UNION ALL SELECT 201215125,N'张立'
GO
IF OBJECT_ID('course') IS NOT NULL DROP TABLE course
GO
CREATE TABLE course(
cno VARCHAR(20),
cname NVARCHAR(10)
)
GO
INSERT INTO course
SELECT 1,N'数据库'
UNION ALL SELECT 2,N'数学'
UNION ALL SELECT 3,N'信息系统'
UNION ALL SELECT 4,N'操作系统'
UNION ALL SELECT 5,N'数据结构'
UNION ALL SELECT 6,N'数据处理'
UNION ALL SELECT 7,N'PASCAL语言'
GO
IF OBJECT_ID('sc') IS NOT NULL DROP TABLE sc
GO
CREATE TABLE sc(
sno VARCHAR(20),
cno VARCHAR(20),
grade INT
)
GO
INSERT INTO sc
SELECT 201215121, 1, 92
UNION ALL SELECT 201215121, 2, 85
UNION ALL SELECT 201215121, 3, 88
UNION ALL SELECT 201215122, 2, 90
UNION ALL SELECT 201215122, 3, 80
UNION ALL SELECT 201215126, 1, 80
UNION ALL SELECT 201215126, 2, 70
UNION ALL SELECT 201215126, 3, 60
UNION ALL SELECT 201215126, 4, 85
UNION ALL SELECT 201215126, 5, 89
UNION ALL SELECT 201215126, 6, 90
UNION ALL SELECT 201215126, 7, 94
GO
--先查出内部子查询的结果
SELECT SC.sno
FROM sc
GROUP BY
SC.sno
HAVING COUNT(cno) != 7
/*
sno
201215121
201215122
*/

--改为等价写法
/*
原:
SELECT sname
FROM student
WHERE NOT EXISTS
(
SELECT SC.sno
FROM sc
WHERE Student.Sno = sc.sno
GROUP BY
SC.sno
HAVING COUNT(cno) != 7
)
*/
-- ==>
SELECT *
FROM student
LEFT JOIN
(
SELECT SC.sno
FROM sc
GROUP BY
SC.sno
HAVING COUNT(cno) != 7
) AS t ON student.sno=t.sno
--WHERE t.sno IS NULL --为便于观察,暂时不加 where
/*
sno sname sno
-------------------- ---------- --------------------
201215121 李勇 201215121
201215122 刘晨 201215122
201215123 王敏 NULL
201215126 杨天 NULL
201215125 张立 NULL
*/


这样看就非常清晰了吧。

你 #2 的, 写出完整的 sql , 半截运行不了。
吉普赛的歌 版主 2018-10-15
  • 打赏
  • 举报
回复
改成等价写法, 就很容易理解了:
USE tempdb
GO
IF OBJECT_ID('student') IS NOT NULL DROP TABLE student
GO
CREATE TABLE student(
	sno VARCHAR(20),
	sname NVARCHAR(10)	
)
GO
INSERT INTO student
SELECT 201215121,N'李勇'
UNION ALL SELECT 201215122,N'刘晨'
UNION ALL SELECT 201215123,N'王敏'
UNION ALL SELECT 201215126,N'杨天'               
UNION ALL SELECT 201215125,N'张立'
GO
IF OBJECT_ID('course') IS NOT NULL DROP TABLE course
GO
CREATE TABLE course(
	cno VARCHAR(20),
	cname NVARCHAR(10)	
)
GO 
INSERT INTO course
SELECT 1,N'数据库'
UNION ALL SELECT 2,N'数学'
UNION ALL SELECT 3,N'信息系统'                                
UNION ALL SELECT 4,N'操作系统'                                
UNION ALL SELECT 5,N'数据结构'                                
UNION ALL SELECT 6,N'数据处理'                                
UNION ALL SELECT 7,N'PASCAL语言'
GO
IF OBJECT_ID('sc') IS NOT NULL DROP TABLE sc
GO
CREATE TABLE sc(
	sno	VARCHAR(20),
	cno VARCHAR(20),
	grade INT	
)
GO 
INSERT INTO sc
SELECT 201215121,	1,   	92
UNION ALL SELECT 201215121,	2,   	85
UNION ALL SELECT 201215121,	3,  	88
UNION ALL SELECT 201215122,	2,   	90
UNION ALL SELECT 201215122,	3,   	80
UNION ALL SELECT 201215126,	1,   	80
UNION ALL SELECT 201215126,	2,   	70
UNION ALL SELECT 201215126,	3,   	60
UNION ALL SELECT 201215126,	4,   	85
UNION ALL SELECT 201215126,	5,   	89
UNION ALL SELECT 201215126,	6,   	90
UNION ALL SELECT 201215126,	7,   	94
GO
--先查出内部子查询的结果
SELECT SC.sno
FROM   sc
GROUP BY
        SC.sno
HAVING COUNT(cno) != 7
/*
sno
201215121
201215122
*/

--改为等价写法
/*
原:
SELECT sname
FROM   student
WHERE  NOT EXISTS
       (
           SELECT SC.sno
           FROM   sc
           WHERE  Student.Sno = sc.sno
           GROUP BY
                  SC.sno
           HAVING COUNT(cno) != 7
       )
*/
-- ==> 
SELECT *
FROM   student
LEFT JOIN 
       (
           SELECT SC.sno
           FROM   sc
           GROUP BY
                  SC.sno
           HAVING COUNT(cno) != 7
       ) AS t ON student.sno=t.sno
--WHERE t.sno IS NULL    --为便于观察,暂时不加 where
/*
sno                  sname      sno
-------------------- ---------- --------------------
201215121            李勇         201215121
201215122            刘晨         201215122
201215123            王敏         NULL
201215126            杨天         NULL
201215125            张立         NULL
*/
这样看就非常清晰了吧。 你 #2 的, 写出完整的 sql , 半截运行不了。
yyouyou 2018-10-15
  • 打赏
  • 举报
回复
上面的漏掉了一个select sname
以下语句也是正确的
select sname
from student
where not exists
(select *
from sc
where Student.Sno=sc.sno

having count(cno)!=7)
yyouyou 2018-10-15
  • 打赏
  • 举报
回复
引用 1 楼 yenange 的回复:
可能是因为 null != 7


改成这样,去掉了group by ,也是正确的结果,哎真是搞不懂了

from student
where not exists
(select *
from sc
where Student.Sno=sc.sno

having count(cno)!=7)
吉普赛的歌 版主 2018-10-15
  • 打赏
  • 举报
回复
可能是因为 null != 7

34,575

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧