SQL 語言:結構化的查詢語言(Structured Query Language),是關系數據庫管理系統的標准語言。是一種解釋語言,寫一句執行一句,不需要整體編譯執行。
語法特點:
語法:
create database 數據庫名稱
on primary --默認在主文件組上
(
name='邏輯名稱_data' , --當你發現它不是一句完整的sql語句,而僅僅是一個處理結構中的某一句的時候,就需要添加 ,
size=初始大小, --數值不包含在‘’以內
filegrowth=文件增長 ,
maxsize=最大容量,
filename='物理路徑'
)
log on
(
name='邏輯名稱_log' , --當你發現它不是一句完整的sql語句,而僅僅是一個處理結構中的某一句的時候,就需要添加 ,
size=初始大小, --數值不包含在‘’以內
filegrowth=文件增長 ,
maxsize=最大容量, --一般來說日志文件不限制最大容量
filename='物理路徑'
)
示例:
--顯示具體班級的名稱
select StudentNo,StudentName,
case ClassId --如果case後面接有表達式或者字段,那麼這種結構就只能做等值判斷,真的相當於switch..case
when 1 then '一班'
when 2 then '2班'
when 3 then '3班'
when null then 'aa' --不能判斷null值
else '搞不清白'
end,
sex
from Student
--2.做范圍判斷,相當於if..else,它可以做null值判斷
--case --如果沒有表達式或者字段就可實現范圍判斷
-- when 表達式 then 值 --不要求表達式對同一字段進行判斷
-- when 表達式 then 值
-- .....
--else 其它情況
--end
select StudentNo,StudentName,
case
when BornDate>'2000-1-1' then '小屁孩'
when BornDate>'1990-1-1' then '小青年'
when BornDate>'1980-1-1' then '青年'
--when Sex='女' then '是女的'
when BornDate is null then '出生不詳'
else '中年'
end
from Student
--百分制轉換為素質教育 90 -A 80--B 70 --C 60 --D <60 E NULL--沒有參加考試
select StudentNo,SubjectId,
case
when StudentResult>=90 then 'A'
when StudentResult>=80 then 'B'
when StudentResult>=70 then 'C'
when StudentResult>=60 then 'D'
when StudentResult is null then '沒有參加考試'
else 'E'
end 成績,
ExamDate
from Result
1.沒有{},使用begin..end.如果後面只有一句,可以不使用begin..end包含
2.沒有bool值,只能使用關系運算符表達式
3.也可以嵌套和多重
4.if後面的()可以省略
示例:
declare @subjectname nvarchar(50)='office' --科目名稱declare @subjectId int=(select Subjectid from Subject where SubjectName=@subjectname) --科目IDdeclare @avg int --平均分set @avg=(select AVG(StudentResult) from Result where SubjectId=@subjectId and StudentResult is not null) --獲取平均分print @avgif @avg>=60beginprint '成績不錯,輸出前三名:'select top 3 * from Result where SubjectId=@subjectId order by StudentResult descendelsebeginprint '成績不好,輸出後三名:'select top 3 * from Result where SubjectId=@subjectId order by StudentResultend
沒有{},使用begin..end
沒有bool值,需要使用條件表達式
可以嵌套
也可以使用break,continue
示例:
go
declare @subjectName nvarchar(50)='office' --科目名稱
declare @subjectId int--科目ID
declare @classid int =(select classid from Subject where SubjectName=@subjectName) --查詢當前科目屬於那一個班級
set @subjectId=(select SubjectId from Subject where SubjectName=@subjectName) --獲取科目ID
declare @totalCount int --總人數 :那一個班級需要考試這一科目
set @totalCount=(select COUNT(*) from Student where ClassId=@classid)
print @totalcount --14
declare @unpassNum int --不及格人數
set @unpassNum=(select COUNT(distinct Studentno) from Result where SubjectId=@subjectId and StudentNo in(select StudentNo from Student where ClassId=@classid) and StudentResult<60)
while(@unpassNum>@totalCount/2)
begin
--執行循環加分
update Result set StudentResult+=2 where SubjectId=@subjectId and StudentNo in(select StudentNo from Student where ClassId=@classid) and StudentResult<=98
--重新計算不及格人數
set @unpassNum=(select COUNT(distinct Studentno) from Result where SubjectId=@subjectId and StudentNo in(select StudentNo from Student where ClassId=@classid) and StudentResult<60)
end
go
declare @subjectName nvarchar(50)='office' --科目名稱
declare @subjectId int--科目ID
declare @classid int =(select classid from Subject where SubjectName=@subjectName) --查詢當前科目屬於那一個班級
set @subjectId=(select SubjectId from Subject where SubjectName=@subjectName) --獲取科目ID
declare @totalCount int --總人數
set @totalCount=(select COUNT(*) from Student where ClassId=@classid)
print @totalcount --14
declare @unpassNum int --不及格人數
while(1=1)
begin
set @unpassNum=(select COUNT(distinct Studentno) from Result where SubjectId=@subjectId and StudentNo in(select StudentNo from Student where ClassId=@classid) and StudentResult<60)
if(@unpassNum>@totalCount/2)
update Result set StudentResult+=2 where SubjectId=@subjectId and StudentNo in(select StudentNo from Student where ClassId=@classid) and StudentResult<=98
else
break
end
子查詢,是一個查詢中包含另外一個查詢。
1.子查詢的使用方式:使用()包含子查詢
2.子查詢分類:
1)獨立子查詢:子查詢可以直接獨立運行,例如:
查詢比“王八”年齡大的學員信息
select * from Student where BornDate<(select BornDate from Student where StudentName='王八')
2)相關子查詢:子查詢使用了父查詢中的結果
示例:
--子查詢的三種使用方式
--1.子查詢做為條件,子查詢接在關系運算符後面 > < >= <= = <> !=,如果是接這關系運算符後面,必須保證 子查詢只返回一個值
--查詢六期班的學員信息
select * from Student where ClassId=(select ClassId from grade where classname='八期班')
--子查詢返回的值不止一個。當子查詢跟隨在 =、!=、<、<=、>、>= 之後,或子查詢用作表達式時,這種情況是不允許的。
select * from Student where ClassId=(select ClassId from grade)
--查詢八期班以外的學員信息
--當子查詢返回多個值(多行一列),可以使用in來指定這個范圍
select * from Student where ClassId in(select ClassId from grade where classname<>'八期班')
--當沒有用 EXISTS 引入子查詢時,在選擇列表中只能指定一個表達式。如果是多行多列或者一行多列就需要使用exists
--使用 EXISTS 關鍵字引入子查詢後,子查詢的作用就相當於進行存在測試。外部查詢的 WHERE 子句測試子查詢返回的行是否存在
select * from Student where EXISTS(select * from grade)
select * from Student where ClassId in(select * from grade)
--2.子查詢做為結果集--
select top 5 * from Student --前五條
--使用top分頁
select top 5 * from Student where StudentNo not in(select top 5 studentno from Student)
--使用函數分頁 ROW_NUMBER() over(order by studentno),可以生成行號,排序的原因是因為不同的排序方式獲取的記錄順序不一樣
select ROW_NUMBER() over(order by studentno),* from Student
--查詢擁有新生成行號的結果集 注意:1.子查詢必須的別名 2.必須為子查詢中所有字段命名,也就意味著需要為新生成的行號列命名
select * from (select ROW_NUMBER() over(order by studentno) id,* from Student) temp where temp.id>0 and temp.id<=5
select * from (select ROW_NUMBER() over(order by studentno) id,* from Student) temp where temp.id>5 and temp.id<=10
select * from (select ROW_NUMBER() over(order by studentno) id,* from Student) temp where temp.id>10 and temp.id<=15
--3.子查詢還可以做為列的值
select (select studentname from student where studentno=result.studentno),(select subjectname from subject where subjectid=result.SubjectId), StudentResult from Result
--使用Row_number over()實現分頁
--1.先寫出有行號的結果集
select ROW_NUMBER() over(order by studentno),* from Student
--2.查詢有行號的結果集 子查詢做為結果集必須添加別名,子查詢的列必須都有名稱
select * from (select ROW_NUMBER() over(order by studentno) id,* from Student) temp where id>0 and id<=5
--查詢年齡比“廖楊”大的學員,顯示這些學員的信息
select * from Student where BornDate<(select BornDate from Student where StudentName='廖楊')
--查詢二期班開設的課程
select * from Subject where ClassId=(select ClassId from grade where classname='二期班')
--查詢參加最近一次“office”考試成績最高分和最低分
--1查詢出科目 ID
select subjectid from Subject where SubjectName='office'
--2.查詢出這一科目的考試日期
select MAX(ExamDate) from Result where SubjectId=(select subjectid from Subject where SubjectName='office')
--3,寫出查詢的框架
select MAX(StudentResult),MIN(StudentResult) from Result where SubjectId=() and ExamDate=()
--4.使用子查詢做為條件
select MAX(StudentResult),MIN(StudentResult) from Result where SubjectId=(
select subjectid from Subject where SubjectName='office'
) and ExamDate=(
select MAX(ExamDate) from Result where SubjectId=(
select subjectid from Subject where SubjectName='office'
)
)
--1.inner join :能夠找到兩個表中建立連接字段值相等的記錄
--查詢學員信息顯示班級名稱
select Student.StudentNo,Student.StudentName,grade.classname
from Student
inner join grade on Student.ClassId=grade.ClassId
--左連接: 關鍵字前面的表是左表,後面的表是右表
--左連接可以得到左表所有數據,如果建立關聯的字段值在右表中不存在,那麼右表的數據就以null值替換
select PhoneNum.*,PhoneType.*
from PhoneNum
left join PhoneType on PhoneNum.pTypeId=PhoneType.ptId
--右連接: 關鍵字前面的表是左表,後面的表是右表
--右連接可以得到右表所有數據,如果建立關聯的字段值在右左表中不存在,那麼左表的數據就以null值替換
select PhoneNum.*,PhoneType.*
from PhoneNum
right join PhoneType on PhoneNum.pTypeId=PhoneType.ptId
--full join :可以得到左右連接的綜合結果--去重復
select PhoneNum.*,PhoneType.*
from PhoneNum
full join PhoneType on PhoneNum.pTypeId=PhoneType.ptId
事務處理,要麼都能成功執行,要麼都不執行。
事務的四個特點 ACID:
使用事務:
將你需要操作的sql命令包含在事務中
1.在事務的開啟和事務的提交之間
2.在事務的開啟和事務的回滾之間
三個關鍵語句:
開啟事務:begin transaction
提交事務:commit transaction
回滾事務:rollback transaction
declare @num int =0 --記錄操作過程中可能出現的錯誤號
begin transaction
update bank set cmoney=cmoney-500 where name='aa'
set @num=@num+@@ERROR
--說明這一句的執行有錯誤 但是不能在語句執行的過程中進行提交或者回滾
--語句塊是一個整體,如果其中一句進行了提交或者回滾,那麼後面的語句就不再屬於當前事務,
--事務不能控制後面的語句的執行
update bank set cmoney=cmoney+500 where name='bb'
set @num=@num+@@ERROR
select * from bank
if(@num<>0 ) --這個@@ERROR只能得到最近一一條sql語句的錯誤號
begin
print '操作過程中有錯誤,操作將回滾'
rollback transaction
end
else
begin
print '操作成功'
commit transaction
end
--事務一旦開啟,就必須提交或者回滾
--事務如果有提交或者回滾,必須保證它已經開啟
視圖是一張虛擬表,可以像使用子查詢做為結果集一樣使用視圖
select * from vw_getinfo
使用代碼創建視圖
語法:
create view vw_自定義名稱
as
查詢命令
go
--查詢所有學員信息
if exists(select * from sysobjects where name='vw_getAllStuInfo')
drop view vw_getAllStuInfo
go --上一個批處理結果的標記
create view vw_getAllStuInfo
as
--可以通過聚合函數獲取所以記錄數
select top (select COUNT(*) from Student) Student.StudentNo,Student.StudentName,grade.ClassId,grade.classname from Student
inner join grade on Student.ClassId=grade.ClassId order by StudentName --視圖中不能使用order by
--select * from grade --只能創建一個查詢語句
--delete from grade where ClassId>100 --在視圖中不能包含增加刪除修改
go
--使用視圖。。就像使用表一樣
select * from vw_getAllStuInfo
--對視圖進行增加刪除和修改操作--可以對視圖進行增加刪除和修改操作,只是建議不要這麼做:所發可以看到:如果操作針對單個表就可以成功,但是如果 多張的數據就會報錯:不可更新,因為修改會影響多個基表。
update vw_getAllStuInfo set classname='asdas' ,studentname='aa' where studentno=1
觸發器:執行一個可以改變表數據的操作(增加刪除和修改),會自動觸發另外一系列(類似於存儲過程中的模塊)的操作。
語法:
create trigger tr_表名_操作名稱
on 表名 after|instead of 操作名稱
as
go
if exists(select * from sysobjects where name='tr_grade_insert')
drop trigger tr_grade_insert
go
create trigger tr_grade_insert
on grade for insert ---為grade表創建名稱為tr_grade_insert的觸發器,在執行insert操作之後觸發
as
declare @cnt int
set @cnt = (select count(*) from student)
select * ,@cnt from student
select * from grade
go
--觸發器不是被調用的,而是被某一個操作觸 發的,意味著執行某一個操作就會自動觸發 觸發器
insert into grade values('fasdfdssa')
---替換觸 發器:本來需要執行某一個操作,結果不做了,使用觸 發器中的代碼語句塊進行替代
if exists(select * from sysobjects where name='tr_grade_insert')
drop trigger tr_grade_insert
go
create trigger tr_grade_insert
on grade instead of insert ---為grade表創建名稱為tr_grade_insert的觸發器,在執行insert操作之後觸發
as
declare @cnt int
set @cnt = (select count(*) from student)
select * ,@cnt from student
select * from grade
go
insert into grade values('aaaaaaaaaaaa')
go
---觸 發器的兩個臨時表:
--inserted: 操作之後的新表:所有新表與原始的物理表沒有關系,只與當前操作的數據有關
--deleted:操作之前的舊表:所有新表與原始的物理表沒有關系,只與當前操作的數據有關
if exists(select * from sysobjects where name='tr_grade_insert')
drop trigger tr_grade_insert
go
create trigger tr_grade_insert
on grade after insert
as
print '操作之前的表:操作之前,這一條記錄還沒有插入,所以沒有數據'
select * from deleted
print '操作之後的表:已經成功插入一條記錄,所有新表中有一條記錄'
select * from inserted
go
--測試:
insert into grade values('aaaaa')
if exists(select * from sysobjects where name='tr_grade_update')
drop trigger tr_grade_update
go
create trigger tr_grade_update
on grade after update
as
print '操作之前的表:存儲與這個修改操作相關的沒有被修改之前的記錄'
select * from deleted
print '操作之後的表:存儲這個操作相關的被修改之後 記錄'
select * from inserted
go
--測試
update grade set classname=classname+'aa' where ClassId>15
if exists(select * from sysobjects where name='tr_grade_delete')
drop trigger tr_grade_delete
go
create trigger tr_grade_delete
on grade after delete
as
print '操作之前的表:存儲與這個修改操作相關的沒有被刪除之前的記錄'
select * from deleted
print '操作之後的表:存儲這個操作相關的被刪除之後 記錄--沒有記錄'
select * from inserted
go
--測試
delete from grade where ClassId>15
參數,返回值,參數默認值,參數:值的方式調用
在調用的時候有三個對應:類型對應,數量對應,順序對應
創建語法:
create proc usp_用戶自定義名稱
對應方法的形參 --(int age, out string name)
as
對應方法體:創建變量,邏輯語句,增加刪除修改和查詢..return返回值
go
調用語法:
Exec 存儲過程名稱 實參,實參,實參 ...
示例:
--獲取所有學員信息
if exists(select * from sysobjects where name='usp_getAllStuInfo')
drop proc usp_getAllStuInfo
go
create procedure usp_getAllStuInfo
as
select * from Student
go
--調用存儲過程,獲取的有學員信息
execute usp_getAllStuInfo
--exec sp_executesql 'select * from Student'
--查詢指定性別的學員信息
go
if exists(select * from sysobjects where name='usp_getAllStuInfoBySex')
drop proc usp_getAllStuInfoBySex
go
create procedure usp_getAllStuInfoBySex
@sex nchar(1) --性別 參數不需要declare
as
select * from Student where Sex=@sex
go
--調用存儲過程,獲取指定性別的學員信息
Exec usp_getAllStuInfoBySex '女'
--創建存儲過程獲取指定班級和性別的學員信息
go
if exists(select * from sysobjects where name='usp_getAllStuInfoBySexandClassName')
drop proc usp_getAllStuInfoBySexandClassName
go
create procedure usp_getAllStuInfoBySexandClassName
@classname nvarchar(50), --班級名稱
@sex nchar(1)='男'--性別 有默認的參數建議寫在參數列表的最後
as
declare @classid int ---班級ID
set @classid=(select classid from grade where classname=@classname) --通過參數班級名稱獲取對應的班級ID
select * from Student where Sex=@sex and ClassId=@classid
go
--執行存儲過程獲取指定班級和性別的學員信息
--exec usp_getAllStuInfoBySexandClassName '八期班'
exec usp_getAllStuInfoBySexandClassName default, '八期班' --有默認值的參數可以傳遞default
exec usp_getAllStuInfoBySexandClassName @classname='八期班' --也可以通過參數=值的方式調用
exec usp_getAllStuInfoBySexandClassName @classname='八期班' ,@sex='女'
exec usp_getAllStuInfoBySexandClassName @classname='八期班',@sex='女'
--創建存儲過程,獲取指定性別的學員人數及總人數
go
if exists(select * from sysobjects where name='usp_getCountBySexandClassName')
drop proc usp_getCountBySexandClassName
go
create procedure usp_getCountBySexandClassName
@cnt int=100 output, --output標記說明它是一個輸出參數。output意味著你向服務器請求這個參數的值,那麼在執行的時候,服務器發現這個參數標記了output,就會將這個參數的值返回輸出
@totalnum int =200output, --總人數
@className nvarchar(50), --輸入參數沒有默認值,在調用的時候必須傳入值
@sex nchar(1)='男'--輸入參數有默認值,用戶可以選擇是否傳入值
as
declare @classid int ---班級ID
set @classid=(select classid from grade where classname=@classname) --通過參數班級名稱獲取對應的班級ID
select * from Student where Sex=@sex and ClassId=@classid
set @cnt= (select COUNT(*) from Student where Sex=@sex and ClassId=@classid) --獲取指定班級和性別的總人數
set @totalnum=(select COUNT(*) from Student) ----獲取總人數
go
--調用存儲過程,獲取指定性別的學員人數及總人數
declare @num int,@tnum int
exec usp_getCountBySexandClassName @cnt=@num output ,@totalnum=@tnum output , @className='八期班'
print @num
print @tnum
print '做完了'
---獲取指定班級的人數
if exists(select * from sysobjects where name='usp_getCount')
drop proc usp_getCount
go
create procedure usp_getCount
@className nvarchar(50)='八期班'
as
declare @classid int=(select classid from grade where classname=@className)
declare @cnt int
set @cnt =(select COUNT(*) from Student where ClassId=@classid)
--return 只能返回int整數值
--return '總人數是'+cast(@cnt as varchar(2))
return @cnt
go
--調用存儲過程,接收存儲過程的返回值
declare @count int
--set @count=(exec usp_getCount)
exec @count=usp_getCount '八期班'
print @count
if exists(select * from sysobjects where name='usp_getClassList')
drop proc usp_getClassList
go
create procedure usp_getClassList
as
select classid,classname from grade
go
if exists(select * from sysobjects where name='usp_getPageData')
drop proc usp_getPageData
go
create procedure usp_getPageData
@totalPage int output,--總頁數
@pageIndex int =1 ,--當前頁碼,默認是第一頁
@pageCount int =5 --每一頁顯示的記錄數
as
select * from (select ROW_NUMBER() over(order by studentno) id,* from Student) temp where temp.id>(@pageindex-1)*@pagecount and temp.id<=(@pageindex*@pagecount)
set @totalPage=CEILING((select COUNT(*) from Student)*1.0/@pageCount)
go
select * from sysindexes
--create index IX_Student_studentName
--on 表名(字段名)
--clustered index:聚集索引 nonclustered index--非聚集索引
if exists(select * from sysindexes where name='IX_Student_studentName')
drop index student.IX_Student_studentName
go
create clustered index IX_Student_studentName
on student(studentname)
--如果是先創建主鍵再創建聚集索引就不可以,因為主鍵默認就是聚集索引
--但是如果先創建聚集索引,那麼還可以再創建主鍵,因為主鍵不一定需要是聚集的
--創建局部臨時表
create table #newGrade
(
classid int ,
classname nvarchar(50)
)
---局部臨時表只有在當前創建它的會話中使用,離開這個會話臨時表就失效.如果關閉創建它的會話,那麼臨時表就會消失
insert into #newGrade select * from grade
select * from #newGrade
select * into #newnewnew from grade
select * into newGrade from #newgrade
--創建全局臨時表:只要不關閉當前會話,全局臨時表都可以使用,但是關閉當前會話,全局臨時表也會消失
create table ##newGrade
(
classid int ,
classname nvarchar(50)
)
drop table ##newGrade
select * into ##newGrade from grade
select * from ##newGrade
--創建表變量
declare @tb table(cid int,cname nvarchar(50))
insert into @tb select * from grade
select * from @tb