SQL Server 数据查询 至少的问题

设学生选课库中有3个数据表:
S(sno,sname,birthday,sdeptartment,tel,sex),
SC(sno,cno,grade), C(cno,cname,teacher,pcno)。
检索至少选修课程“数据结构”和“C语言”的学生学号;
给个代码,还有类似的问题是怎么思考的。至少 至多 最少 最多之类的
查询里加 至少 加与不加一样的
比如说 查询选修课程“数据结构”和“C语言”的学生
结果应该一样的 只要他选修的课程里包含这两门就可以了

1、至少即:
结果集={“数据结构”AND“C语言”}U{其他集合}

2、至多即:
结果集={无选课}U{有且仅有“数据结构”}U{有且仅有“C语言”}U{有且仅有“数据结构”和“C语言”}

这里,以lzx_88的答案为反例,
至少问题:
select s.sno from S a,SC b ,C c where s.sno=b.sno and b.cno=c.cno and cname = '数据结构' and cname='C语言'

这是绝对错误的,and cname = '数据结构' and cname='C语言',这句,你会发现你完全检索不出任何信息。这就是典型的想当然的做法。

——————————————————————————————
这里我说说思路,上边的答案也就dsheen的靠谱一些,其余的人检索出来的都是错的。
比如,
select s.sno from S s ,SC sc ,C c where s.sno=sc.sno and sc.cno=c.cno and cname in ('数据结构','C语言');

select s.sno from S s ,SC sc ,C c where s.sno=sc.sno and sc.cno=c.cno and (cname = '数据结构' or cname = 'C语言');

举个例子,若有一个学生A,只选择了 '数据结构' 这门课,那么,按照他们的语句,结果集也包含了这个学生的记录。但实际上,A仅有 '数据结构' 这门课,并不符合我们 至少选修课程“数据结构”和“C语言” 这个要求。我们的要求是,这个学生必须选择了 “数据结构”和“C语言” 这两门课,至于有没有其他的课无所谓,但他的课表中必须拥有这两门课。

明确了需求,我们看看如何编写:
首先,我们无法保证每个学生所选的课均只有一条记录,那么,需使用distinct排除重复记录。其次,使用group 根据学号对记录编组,这样就能统计每个学号选了多少门课。然后,检索数据,再查看分组统计值是否等于2,若是,则证明有两条记录存在。由于我们使用了distinct,则证明了这两条记录肯定是“数据结构”和“C语言”(而不是重复的“数据结构”或者“C语言”的记录)
select s.sno from sc inner join s on sc.sno=s.sno inner join c on sc.cno=c.cno where c.cname='数据结构' or c.cname='C语言' group by sc.sno having count( distinct c.cname)=2;

对于至多的含义,我们要实现 有且仅有 的概念。有 容易实现,但仅有,就得通过 非 计算了。
注:这里很多人会犯想当然的错误,比如,用AND去实现 仅有 的目的。这是不对的,是因为没将行的属性和列的属性区分开来。要使用AND实现必须进行行列转换。这也是写SQL经常犯错的地方。
举个例子,根据一开始给出的计算式,那么,{有且仅有“数据结构”}这一个子集,不能简单地用
select s.sno from sc inner join s on sc.sno=s.sno inner join c on sc.cno=c.cno where c.cname='数据结构'
来实现。这样的语句,实现的仅仅是 有 这个功能。因为某个学生可能不仅仅只选了'数据结构'这门课,但你这样的查询,却把他包含进去了。结果就不对了。
看起来相当复杂,不过,SQL的艺术就在此,你可以通过逻辑运算进行等价,如果你足够牛逼的话,你可能会发现非常完美的方法去找出你需要的结果。
此处进行简单的等价为:
所有选择了“数据结构”或者“C语言”,且总课程数小于等于2的学生
加上
所有的未选择课程的学生

这个可等价为:
1、所有选择了两门课的学生中,他们的两门课是 “数据结构”和“C语言”。
2、所有选择了一门课的学生中,他们的这一门课是“数据结构”或者“C语言”。
3、所有未选择课程的学生。
使用Union将结果集合并,即为结果。

不过这样写出来也太长了,可再进一步等价。

1、检索出所有选择了 “数据结构”或者“C语言”的学生。设为记录集A
2、检索A记录中学生所选择的 非 “数据结构”且 非“C语言”的记录,设为B。
3、A-B即为所求结果集

语句如下:

select distinct s.sno from sc inner join s on sc.sno=s.sno inner join c on sc.cno=c.cno where (c.cname='Course01' or c.cname='Course02')
and s.sno not in
(
select distinct s.sno from sc inner join s on sc.sno=s.sno inner join c on sc.cno=c.cno where c.cname<>'Course01' and c.cname<>'Course02'
)
union
select s.sno from s where s.sno not in
(
select sc.sno from sc
);

不知不觉打了这么多,并不是为了分数什么的,只是我觉得,我自己也有必要去搞清楚这个问题。另外,那个至多的问题,我还没深入想,用了两次表连接,我觉得应该有办法再进行进一步优化的。
温馨提示:答案为网友推荐,仅供参考
第1个回答  2009-09-22
SELECT s1.sno
FROM sc AS s1,sc as s2,c AS c1,c as c2
where s1.cno = c1.cno
and s2.cno=c2.cno
and c1.cname='数据结构'
and c2.cname='C语言'
and s1.sno=s2.sno本回答被提问者采纳
第2个回答  2009-09-22
S(sno,sname,birthday,sdeptartment,tel,sex)
SC(scno,sno,cno,grade)--这里要添个scno也是主键。
C(cno,cname,teacher,pcno)

select s.sno from S s ,SC sc ,C c where s.sno=sc.sno and sc.cno=c.cno and cname in ('数据结构','C语言');
第3个回答  2009-09-23
至少问题:
select s.sno from S a,SC b ,C c where s.sno=b.sno and b.cno=c.cno and cname = '数据结构' and cname='C语言'

至多问题:
select s.sno from S a,SC b ,C c where s.sno=b.sno and b.cno=c.cno and (cname = '数据结构' or cname='C语言')
第4个回答  2009-09-22
这不是书上的例题吗?!
select s.sno from S s ,SC sc ,C c where s.sno=sc.sno and sc.cno=c.cno and (cname = '数据结构' or cname = 'C语言');
相似回答