以下操作均在Oracle數據庫下運行,在某些地方的語法可能與MySQL不同。
另外,是否區分大小寫也有不同。(MySQL與Oracle的大小寫問題)
SQL語言集數據定義、數據操縱、數據查詢、數據控制功能於一體。
數據定義:create,drop,alter
數據操縱:增(insert into … ),刪(delete from …),改(update … set …)
數據查詢:select
數據控制:grant(授予權限),revoke(收回權限)
本文將介紹數據定義、數據操縱、數據查詢在Oracle數據庫下的基本語法(數據控制的語法詳見此文)。
一、數據定義(create,alter,drop)
1.建立基本表
創建教材中的學生表(Student)、學生選課表(SC)、課程表(Course)
(1)學生表:Student (Sno,Sname,Sage,Ssex,Sdept),其中學號Sno爲主碼。
create table Student
(
Sno number primary key,
Sname varchar2(10),
Sage int,
Ssex char(2),
Sdept varchar2(10)
);
(2)課程表:Course (Cno, Cname, Cpno, Ccredit)其中課程號Cno主碼;先行課爲外碼參照Course表中Cno字段。
create table Course
(
Cno number primary key,
Cname varchar2(10),
Cpno varchar2(10) references Course(Cno),
Ccredit int
);
(3)學生選課表:SC(Sno, Cno, Grade)其中學號Sno、課程號Cno爲主碼;Sno爲外碼參照Student表中Sno字段;Cno爲外碼參照Course表中Cno字段。
create table SC
(
Sno number references Student(Sno),
Cno number references Course(Cno),
Grade int,
primary key (Sno,Cno)
);
2.修改基本表
(1)在Student表中加入屬性BloodType【char(2)型】。
alter table Student add BloodType char(2);
(2)修改表Student中的Sdept屬性的數據類型爲varchar2(40),注意和定義表的時候類型不同。
alter table Student modify Sdept varchar2(40);
(3)給表Student的sage列添加一個自定義約束,sage必須大於15且小於30。
alter table Student add constraint age_ck check(Sage>15 and Sage<30);
(4)刪除(3)中新添加的約束。
alter table Student drop constraint age_ck;
(5)SC表中的sno增加外鍵約束f_sno,參照Student表中的sno字段。
alter table sc add constraint f_sno foreign key (sno) references student(sno);
(6)刪除表Student中的字段BloodType。
alter table Student drop (BloodType); #記得加括號,不加括號就要在drop前面寫column
3.刪除基本表
(1)刪除基本表Student。
drop table Student;
(2)刪除基本表SC。
drop table SC;
4.索引操作
(1)在SC表上建立關於Sno升序、Cno降序的唯一索引i_sc+學號後四位。
create unique index i_sc on SC(Sno asc,Cno desc,substr(Sno,-4));
(2)刪除Course表上的索引i_sc。
drop index i_sc;
二、數據操縱(insert,update,delete)
1.插入數據
1)向Student表中插入數據
2)向Course表中插入數據
3)向SC表中插入數據
可參考如下數據,也可不參考。
insert into STUDENT(SNO,SNAME,SSEX,SAGE,SDEPT) values(200215121,'李勇','男',20,'CS');
insert into STUDENT(SNO,SNAME,SSEX,SAGE,SDEPT) values(200215122,'劉晨','女',19,'CS');
insert into STUDENT(SNO,SNAME,SSEX,SAGE,SDEPT) values(200215123,'王敏','女',18,'MA');
insert into STUDENT(SNO,SNAME,SSEX,SAGE,SDEPT) values(200215125,'張立','男',19,'IS');
# 記得先把COURSE表中的外鍵約束關了,否則數據插不進去
insert into COURSE(CNO,CNAME,CPNO,CCREDIT) values(1,'數據庫',5,4);
insert into COURSE(CNO,CNAME,CPNO,CCREDIT) values(2,'數學',null,2);
insert into COURSE(CNO,CNAME,CPNO,CCREDIT) values(3,'信息系統',1,4);
insert into COURSE(CNO,CNAME,CPNO,CCREDIT) values(4,'操作系統',6,3);
insert into COURSE(CNO,CNAME,CPNO,CCREDIT) values(5,'數據結構',7,4);
insert into COURSE(CNO,CNAME,CPNO,CCREDIT) values(6,'數據處理',null,2);
insert into COURSE(CNO,CNAME,CPNO,CCREDIT) values(7,'PASCAL語言',6,4);
insert into SC(SNO,CNO,GRADE) values(200215121,1,92);
insert into SC(SNO,CNO,GRADE) values(200215121,2,85);
insert into SC(SNO,CNO,GRADE) values(200215121,3,88);
insert into SC(SNO,CNO,GRADE) values(200215122,4,90);
insert into SC(SNO,CNO,GRADE) values(200215122,3,80);
2.修改數據
1)將王敏的同學的年齡改爲20。
update STUDENT set sage=20 where sname='王敏';
2)將全部同學的年齡加1。
update STUDENT set sage=sage+1;
3)將’CS’系同學的選課信息中的成績置0。
update SC set grade=0 where sno in
(
select sc.sno from STUDENT join SC on(student.sno=sc.sno)
where sdept='CS'
);
3.刪除數據
1)刪除和’劉晨’在同一個系的學生的信息。(包括劉晨自己也會被刪除)
delete from STUDENT where sdept in
(
select sdept from STUDENT
where sname='劉晨'
);
然後發現刪除不了,因爲有外鍵約束,SC表依賴當前表的SNO,
所以要先刪掉SC表中SNO的外鍵約束alter table sc drop constraint SYS_C0051208;
再執行刪除語句即可。
2)刪除’CS’系同學的選課信息。
delete from SC where sno in
(
select sno from STUDENT
where sdept='CS'
);
三、數據查詢(select)
1.包括排序、分組的單表查詢
(1)求數學系學生的學號和姓名。
select sno,sname from student where sdept='MA';
(2)求選修了課程的學生學號。
# 學號distinct去重,因爲SC表中學號可以重複,一個學號可選多門課
select distinct sno from sc;
(3)求選修課程號爲‘2’的學生號和成績,並要求對查詢結果按成績的降序排列,如果成績相同按學號的升序排列。
select sno,grade from sc where cno=2 order by grade DESC,sno ASC;
(4)求選修課程號爲’2’且成績在80~90之間的學生學號和成績,並將成績乘以0.8輸出。
select sno,grade*0.8 from sc where cno=2 and grade>=80 and grade<=90;
(5)求數學系或計算機系姓張的學生的信息。
# 注意and的優先級高於or,加一個括號即可
select * from student where sname like '張%' and (sdept='MA' or sdept='CS');
(6)求缺少了成績的學生的學號和課程號。
select sno,cno from sc where grade is null;
(7)查詢各個課程號與相應的選課人數。
select cno,count(*) from sc group by cno;
2.多表連接查詢
(1)查詢每個學生的情況以及他所選修的課程。
select student.sno,sname,ssex,sdept,cno from student,sc where student.sno=sc.sno;
(2)求學生的學號、姓名、選修的課程及成績。
select student.sno,sname,cno,grade from student,sc where student.sno=sc.sno;
(3)求選修課程號爲‘1’且成績在90分以上的學生學號、姓名和成績。
select student.sno,sname,grade from student,sc where student.sno=sc.sno and cno=1 and grade>=90;
(4)查詢每一門課程的間接先行課。
select c1.cno,c2.cpno from course c1,course c2 where c1.cpno=s2.cno;
(5)查詢與’劉晨’在同一個系學習的學生。
select s1.sno,s1.sname,s1.sage,s1.ssex,s1.sdept
from student s1,student s2
where s1.sdept=s2.sdept and s2.sname='劉晨'; #兩個相同的表通過sdept連接
(6)查詢選修了課程名爲‘信息系統‘的學生學號和姓名。
select sc.sno,sname from student,sc,course
where student.sno=sc.sno and sc.cno=course.cno and cname='信息系統';
(7)查詢平均成績在80分以上的學生學號和平均成績。
select sno,avg(grade) from sc group by sno having avg(grade)>=80;
(8)查詢選修了1門以上課程的學生的學號。
select sno from sc group by sno having count(*)>1;
3.嵌套查詢
(1)求選修了信息系統的學號和姓名。
select sno,sname from student where sno in
(
select sno from sc where cno in
(
select cno from course
where cname='信息系統'
)
);
(2)查詢與劉晨在同一個系學習的學生。
select * from student where sdept in
(
select sdept from student
where sname='劉晨'
);
(3)求選修1號課程的成績高於劉晨的成績(指劉晨選修的所有的課程的成績)的學生學號及成績。
select sno,grade from sc where cno=1 and grade >
(
select max(grade) from sc where sno in
(
select sno from student
where sname='劉晨'
)
);
(4)求其他系中比計算機系某一學生年齡小的學生(即年齡小於計算機系年齡最大者的學生)。
select * from student where sage <
(
select max(sage) from student
where sdept='CS'
);
(5)求其他系中比計算機系學生年齡都小的學生姓名及年齡。
select sname,sage from student where sage <
(
select min(sage) from student
where sdept='CS'
);
(6)求選修課程超過2門的學生的學號和姓名。
select sno,sname from student where sno in
(
select sno from sc
group by sno having count(*)>2
);
(7)求沒有選修3號課程的學生姓名。
select sname from student where not exists
(
select * from sc
where cno=3 and student.sno=sc.sno
);
(8)查詢選修了全部課程的學生姓名。【重點!】
select sname from student where not exists
(
select * from course where not exists
(
select * from sc
where sc.cno=course.cno and sc.sno=student.sno
)
);
分析:
這個比較難懂,我們先看看內兩層查詢,表示選出當前學號(比如說122)沒選的課
select * from course where not exists
(
select * from sc
where sc.cno=course.cno and sc.sno=200215122
);
如果這個結果是空,表示當前學號(比如說122)沒選的課爲空,最外層加一個select sname from student where not exists,表示選出所有 沒有沒選的課 的學生。
可以將not exists當作“減法”理解,內兩層的意思就是把所有的課減去122學號選的課,如果爲空(所有的課被122選的課給減沒了),那麼就選出122來。
(9)求至少選修了學號爲“200215121”的學生所選修全部課程的學生學號和姓名。【重點!】
分析:
先選出121學生選的課 減去 122學生選的課:
select * from sc sc1 where sno=200215121 and not exists
(
select * from sc sc2
where sc1.cno=sc2.cno and sc2.sno=200215122
);
單純的只有where not exist表示選出空的。
以上的整個式子表示減法:最內層用cno連接,表示找選課記錄,然後121選課集合減去122選課集合。
過程的話實際就是兩層for循環遍歷,for(i: 121選課){for (j: 122選課)},對於每個i,判斷122選課中是否存在j滿足i.cno=j.cno,如果有,不爲空,那麼not exists就不選出這個i,實際上這不就相當於當前遍歷到的i的記錄被相同的j減去了嗎!而且外層循環是121選課,說明最終輸出的答案只能是121選課的子集,只要答案爲空我們就把他選出來!
如果爲空,說明122這個學號把121的所有課都選了(所以121的課被減沒了)。
還有一種情況,就是122這個學號不僅把121的所有課都選了,他還選了其他課,這個時候的減法結果不是按“負數”理解,就理解成122把121的所有課都減沒了,他還剩了多餘的課,那是122的選課集合剩了(不是121剩了),最主要的是121被減沒了,所以121的選課集合答案是空。
繞了這麼多,反正核心就是:
找一個學生的選課集合作爲“減數”,如果他大於等於121的選課集合,那麼121的選課集合減去他之後就能變成空,這個“減數”就是我們要找的。
最後,把學號122改成變量,加一個最外層查詢遍歷所有學生,
因爲找到爲空的就要把他選出來,所以最外層寫not exists選出空的,那麼整個答案就是:
select sno,sname from student where not exists
(
select * from sc sc1 where sno=200215121 and not exists
(
select * from sc sc2
where sc1.cno=sc2.cno and sc2.sno=student.sno
)
);