SQL高级总结

第一章:
1.数据库的设计分为三个阶段:
 需求分析阶段:分析客户的业务和数据处理需求
 概要设计阶段:绘制E-R关系图
 详细设计阶段:用数据库的三大范式进行审核,创建数据库和表


2.在E-R关系图中:
 矩形表示实体,椭圆表示属性,菱形表示关系,直线用来连接属性和实体


3.数据库的三大范式:
 1.第一范式:每列(属性)都是不可再分的最小数据单元,即列不可再分
 2.第二范式:确保表中的每列都和主键相关
 3.第三范式:不存在传递依赖关系,确保每列都和主键直接相关,而不是间接相关

注意:存在部分依赖不满足第二范式[订单编号,商品编号](组合键)
    订单日期与订单编号有关,与商品编号无关


       
第二章
1.创建一个数据库文件和日子文件
  if exists(select * from sysdatabases where name='employees')
 drop database employees
  create database employees
  on primary
  (
 name='employees_data',
 filename='D:\project\employees_data.mdf',
 size=10,
 filegrowth=10%
  )   
  ,
  (
 次要数据文件
 name='employees_data2',
 filename='D:\project\employees_data2.ndf',
 size=20,
 filegrowth=1
  ) 
  log on 
  (
 name='employees_log',
 filename='D:\project\employees_log.ldf',
 size=10,
 maxsize=50,
 filegrowth=1
  )
  (
 name='employees_log2',
 filename='D:\project\employees_log2.ldf',
 size=10,
 maxsize=50,
 filegrowth=1
  )


2.删除数据库:
  if exists (select * from sysdatabases where name='stuDB')
 drop database stuDB


3.创建表:
  if exists (select  * from sysobjects where name='stuInfo')
 drop table stuInfo
  create table stuInfo
  (
 字段1  数据类型 是否为空,
 字段2  数据类型 是否为空
  )


4.添加约束:
  alter table stuInfo
 add constraint PK_stuNo primary key (stuNo),
 constraint UQ_stuID unique(stuID),
 constraint DF_stuAddress default('地址不详') for stuAddress,
 constraint CK_stuAge check(stuAge between 15 and 40),
 constraint FK_stuNo foreign key(stuNo) references  stuInfo(stuNo)
 代码创建组合键:
  alter table stuInfo 
 add constraint PK_stuNo primary key (stuNo,stuNo2)   


5.删除约束:
 alter table 表名
   drop constraint 约束名


6.添加一个新的列:
 alter table stuInfo
   add stuBirthday datetime


7.删除一个列:
 alter table stuInfo
   drop column stuBirthday


8.创建登录用户:
 exec sp_grantlogin 'jbtraining\s26301' --window登录用户
 exec sp_addlogin 'zhangsan','1234'

  创建数据库用户:
 exec sp_grantdbaccess 'jbtraining\s26301','s26301DBUser' --window登录
 exec sp_grantdbaccess 'zhangsan','zhangsanDBUser'

  给数据库用户授权:
 grant create table to s26301DBUser
 grant select,insert,update on stuInfo to zhangsanDBuser


第三章
1.变量:@表示局部变量,@@表示全局变量 (一般不声明全局变量)
 declare @name varchar(8)

  同时声明两个变量:declare @name varchar(9),@seat int


2.set和select赋值语句区别:
 set    一次只能给一个变量赋值
 select 一次可以给多个变量赋值,select适用于从表中查出数据给变量赋值的情况
 
  注意:select 赋值和查询不能同时进行


3.两种输出语句:
 print  局部变量或字符串
 select 局部变量 as 自定义列名

  注意:print 打印语句要求只能以一种数据类型打印
 即print '我是的年龄:'+convert(varchar,@age)才行

 
4.常用的全局变量:
 @@error:最近一条SQL语句是否用错误,如果用错误,将返回非零值
 @@identity:可用来查询最后插入的数据的标识值 


5.if (条件)
 begin 
  语句
 end
  else
      ...
  注意:if后面有多条语句的时候,要用begin end


6.while(1=1)
 begin 
   语句
  break
 end


7.case 
 when 条件1 then 结果1
 when 条件2 then 结果2
 else 其他结果
  end 
  注意:可加在SQL语句的任何地方


8.批处理可以提高语句的执行效率,批处理结束的标志是'GO'


9.in 或or 策略性能较低,一般为两个SQL语句的效率更高
 select * from student where stuNo=2 or stuNo=3
 比select * from student where stuNo=2 union select * from student where stuNo=3
 的效率低

 

第四章
1.建立临时表:
 select * into #temp from stuInfo

  临时表保存在临时数据库中
  临时表不会从一个会话状态转移到另一个会话状态(只能在创建临时表的查询中查询)
  当会话状态结束后临时表会自动清除
  与存储过程结合使用


2.子查询
   select * from stuInfo where stuAge >(select * from stuInfo where stuName='小李')
   go

 

第五章
1.事务:事务及一段SQL代码放到事务中,则这段代码执行时要么失败,要么就成功,失败后,之前执行的代码全部回滚
  事务的特性:
        原子性:事务的各元素是不可在分的
        一致性:事务完成后,数据是一致状态
        隔离性:对数据进行修改的所有并发事务是彼此隔离的,一个事务要么在另一个事务之前访问它执行的数据,要么在另一个事务结束后再去访问
        持久性:数据的更改是该在硬盘上的


2.事务应用的代码:
  例子:张三和李四转账
  begin transaction
  declare @errorSum int 
  set @errorSum = 0
  update bank set currentMoney = currentMoney-1000 where customerName='张三'
  set @erroSum = @errorSum+@@error
  update bank set currentMoney = currentMoney+1000 where customerName='李四'
  set @erroSum = @errorSum+@@error
  if @errorSum > 0
 begin 
  print '事务失败,回滚事务'
  rollback transaction
 end 
  else 
 begin 
  print '事务成功,提交事务'
  commit transaction
 end
go


3.索引:缺点:需要更多的硬盘空间,如果插入、更新、删除数据,系统更新索引速度慢
  唯一索引:不允许两行具有相同的索引值 
  主键索引:在创建数据库关系图时,定义为主键列会自动创建主键索引
  聚集索引:索引和列值相同,一个表只能有一个,查询速度快
  非聚集索引:索引和列值不相同,一个表能有<249个,查询速度慢
  
  创建索引:
  if exists(select name from sysindexes where name='IX_stuMarks_writtenExam')
 drop index stuMarks.IX_stuMarks_writtenExam
  create nonclustered index IX_stuMarks_writtenExam
  on stuMarks(writtenExam) ---建议不写with fillfactor=30


4.视图:最大的作用在于:查询,能够实现隐藏一些列的信息,更容易理解和获得数据
  
  创建视图:
  if exists (select * from sysobjects where name ='view_stuInfo_stuMarks')
 drop view view_stuInfo_stuMarks
  go
  create view view_stuInfo_stuMarks
  as 
     select stuName,stuInfo.stuNo,writtenExam,labExam from stuInfo left join stuMarks on stuInfo.stuNo=stuMarks.stuNo
  go
  select * from view_stuInfo_stuMarks   //查询视图中的数据
 


第六章
1.系统存储过程:
  exec sp_databases --列出当前系统中的数据库
  exec sp_renamedb 'Northwind','Northwind1' --更改Northwind数据库名为northwind1
  use stuDB
  go
  exec sp_tables --当前数据库中可查询对象的列表
  exec sp_columns stuInfo --查看表stuInfo中列的信息
  exec sp_help stuInfo --查看表stuInfo的所有信息
  exec sp_helpconstraint stuInfo --查看表stuInfo的约束
  exec sp_helpindex stuMarks --查看stuMarks的索引
  exec sp_helptext 'view_stuInfo_stuMarks' --查看视图的语句文本
  exec sp_stored_procedures --返回当前数据库中的存储过程列表

  
2.用DOS命令创建一个文件夹
  exec xp_cmdshell 'mkdir D:\book',no_output
 

3.创建不带参数的存储过程
  if exists(select  * from sysobjects where name='pro_stu')
 drop procedure pro_stu
  go
  create procedure pro_stu
    as 
        SQL语句
    go

4.创建带输入参数的存储过程
  if exists(select  * from sysobjects where name='pro_stu')
 drop procedure pro_stu
  go
  create procedure pro_stu
    @writtenPass int,
    @labPass int
    as 
        SQL语句
    go

5.创建带输出参数的存储过程
  if exists(select  * from sysobjects where name='pro_stu')
 drop procedure pro_stu
  go
  create procedure pro_stu
    @writtenPass int output,
    @labPass int output
    as 
        SQL语句
    go
   
6.如何接return 值:
   if exists(select  * from sysobjects where name='pro_stu')
 drop procedure pro_stu
   go
   create procedure pro_stu
    @notpassSum int output, 
    @writtenPass int=60,
    @labPass int=60
    as 
        print '笔试及格线:'+convert(varchar,@writtenPass)+'机试及格线:'+convert(varchar,labPass)
 print '参加本次考试没有通过的学员:'
         select  stuName,stuInfo.stuNo,writtenExam,labExam from stuInfo inner join stuMarks on stuInfo.stuNo=stuMarks.stuNo 
  where writtenExam<@writtenPass or labExam<@labPass
        select @notpassSum=count(stuNo) from stuMarks where writtenExam<@writtenPass or labExam<@labPass
   return 12
    go
    
    declare @sum int 
    declare @returnValue int
    注意:
    exec @returnValue = proc_stu @sum output ,64
    if @sum>=3
       print '未通过人数:'+convert(varchar,@sum)+'人,超过60%,及格分数线还应该下调'
    else 
       print '未通过人数:'+convert(varchar,@sum)+'人,已控制在60%已下,及格分数线适中' 


7.raiserror 可以弥补print不足,即可以在程序中显示输出信息
   if exists(select  * from sysobjects where name='pro_stu')
 drop procedure pro_stu
   go
   create procedure pro_stu
    @notpassSum int output, 
    @writtenPass int=60,
    @labPass int=60
    as 
 if(not @writtenPass between 0 and 100) or (not @labPass between 0 and 100)
  begin
  raiserror(' 及格线错误,请指定0-100之间,统计中断退出')
  return 
  end
        print '笔试及格线:'+convert(varchar,@writtenPass)+'机试及格线:'+convert(varchar,labPass)
 print '参加本次考试没有通过的学员:'
         select  stuName,stuInfo.stuNo,writtenExam,labExam from stuInfo inner join stuMarks on stuInfo.stuNo=stuMarks.stuNo 
  where writtenExam<@writtenPass or labExam<@labPass
        select @notpassSum=count(stuNo) from stuMarks where writtenExam<@writtenPass or labExam<@labPass
   return 12
    go
    
    declare @sum int 
    declare @return int
    注意:
    exec @return = proc_stu @sum output ,64
    if @sum>=3
       print '未通过人数:'+convert(varchar,@sum)+'人,超过60%,及格分数线还应该下调'
    else 
       print '未通过人数:'+convert(varchar,@sum)+'人,已控制在60%已下,及格分数线适中' 


8.加密存储过程:
  alter procedure 存储过程名
  with encryption as SQL内容


9.存储过程注意事项:
  (1)不需要有print[打印出的内容不会到程序中显示]
  (2)一般和临时表配合使用
  (3)执行存储过程就是开启一次会话,执行结束后会话状态结束
  (4)和游标配合使用
  (5)存储过程没有重载
  (6)创建存储过程必须在go的后面,否则报错
  (7)存储过程注释:
 /*
   功能
   创建日期
   修改日期
   修改备注
 */ 


10.游标:可以把存储过程返回的集合中的数据一行一行
 --定义游标
 declare mycursor cursor for select * from #tempBook
 --定义参数
 declare @first_day int
 declare @first_pay int
 declare @second_pay int
 declare @pay_day int
 set @total=0
 --打开游标
 open mycursor
 --提取第一条数据
 fetch next from mycursor into @first_day,@first_pay,@second_pay,@pay_day
 while @@fetch_status = 0
   begin
      if @pay_day <= @first_day  --第一种类型
      set @total=@total+@first_pay*@pay_day
      else             --第二种类型
      set @total=@total+@second_pay*(@pay_day-@first_day)+@first_day*@first_pay
      fetch next from mycursor into @first_day,@first_pay,@second_pay,@pay_day
   end
 --关闭游标
 close mycursor 
 --注销游标
 deallocate mycursor  
 GO

 declare @tatal int
 exec book_proc 'F0612S288',@tatal output
 print @tatal

11.触发器:在对表进行插入、更新或删除操作时自动执行的存储过程
   (1).它是一种特殊的存储过程
   (2).也具备事务的功能
   (3).它能在多表之间执行特殊的业务规则
   (4).触发器通常用于强制业务规则
   (5).触发器是一种高级约束,可以定义比用check约束更为复杂的约束,可执行复杂的SQL语句(if/while/case),可引用其它表中的列

   详解:触发器触发时:
 系统自动在内存中创建deleted表或inserted表,只读,不允许修改;触发器执行完成后,自动删除
 inserted 表 :
 临时保存了插入或更新后的记录行,可以从inserted表中检查插入的数据是否满足业务需求,如果不满足,则向用户报告错误消息,并回滚插入操作
 deleted 表
 临时保存了删除或更新前的记录行,可以从deleted表中检查被删除的数据是否满足业务需求,如果不满足,则向用户报告错误消息,并回滚插入操作

   我的理解:当更改一个表的数据的时候,如果为该表创建了触发器,相关的表的数据会自动的更改
   注意:触发器定义在特定的表上,与表相关
  自动触发执行
  不能直接调用
         是一个事务(可回滚)
   
    例子1:insert触发器,在transInfo表上创建触发器,当对transInfo表执行insert语句时自动触发trig_transInfo触发器
 create trigger trig_transInfo 
  on transInfo 
   for[after] insert
    as
     declare @type char(4),@outMoney MONEY
     declare @myCardID char(10),@balance MONEY
     select @type=transType,@outMoney=transMoney,@myCardID=cardID from inserted
       if (@type='支取') 
          update bank set currentMoney=currentMoney-@outMoney where cardID=@myCardID
      else
          update bank set currentMoney=currentMoney+@outMoney where cardID=@myCardID
 go

 
   例子2:delete触发器
 create trigger trig_delete_transInfo
  on transInfo
   for delete
    as
        print '开始备份数据,请稍后......'
        if not exists(select * from sysobjects where name='backupTable')
           select * into backupTable from deleted
       else 
   begin
            insert into backupTable select * from deleted
          print '备份数据成功,备份表中的数据为:'
          select * from backupTable 
   end 
 go 
   
   例子3:update触发器
 create trigger trig_update_bank
  on bank
   for update
    as
        declare @beforeMoney money,@afterMoney money
        select @beforeMoney=currentMoney from deleted   
        select @afterMoney=currentMoney from inserted    
        if ABS(@afterMoney-@beforeMoney)>20000 
           begin
             print '交易金额:'+convert(varchar(8), ABS(@afterMoney-@beforeMoney))
              raiserror('每笔交易不能超过2万元,交易失败',16,1)
              rollback tansaction
            end
 go

    例子4:
 问题:交易日期一般由系统自动产生,默认为当前日期。为了安全起见,一般禁止修改,以防舞弊。 
 update(列名)函数可以检测是否修改了某列 
 create trigger trig_update_transInfo
  on transInfo
   for update 
   as
        if update(transDate)
            begin
              print '交易失败.....'
              raiserror(‘安全警告:交易日期不能修改,由系统自动产生',16,1)
              rollback transaction    
            end
 go

 

课外补充:
1.select *  from table_name1  where exists(select *  from table_name2  where 条件) 

2.image 变长二进制数据,最大长度为2^31-1(2G) 可存图片,电影,等等

3.alter table userInfo
  add constraint CK_PID check(len(PID)=18 or len(PID)=15),
  constraint CK_telephone check(telephone like replicate('[0-9]',4)+'-'+replicate('[0-9]',8)
 or telephone like replicate('[0-9]',3)+'-'+replicate('[0-9]',8) or len(telephone)=11)

4. 联合查询 
   union运算可以把多个查询的结果合并到一个结果集里显示. 
   union运算的一般语法:[表]查询1 union [ALL]查询2 UNION … 
   例:返回巴西所有供给商和客户的名字和城市 
   select companyName,city from suppliers where country = 'Brazil' union select companyName,city from customers where country = 'Brazil'

   注意: 缺省的情况下,union子句不返回重复的记录,如果想显示所有记录,可以加ALL选项 
         union运算要求查询具有(相同数目的字段),但字段数据类型不必相同. 
         每一个查询参数中可以使用GROUP BY子句或HAVING子句进行分组.要想以指定的顺序来显示返回的数据,可以在最后一个查询的尾部使用OREER BY子句.

5.新建默认值 
  alter table [表名] add constraint 默认值名 default '51WINDOWS.NET' for [字段名]

  删除默认值 
  alter table [表名] drop constraint 默认值名

6. 删除Sql Server 中的日志,减小数据库文件大小 
    dump transaction 数据库名 with no_log 
    backup log 数据库名 with no_log 
    dbcc shrinkdatabase(数据库名) 
    exec sp_dboption ’数据库名’, ’autoshrink’, ’true’
  
   示例:
    dump transaction MyDocument with no_log
    backup log MyDocument with no_log
 dbcc shrinkdatabase(MyDocument)
 exec sp_dboption 'MyDocument','autoshrink','true'

7.返回所有有下过采购单的供应商信息,同时还需要返回供应商最后一次下采购单的时间
  select Provider.*,md from Provider
  inner join
  (
 select max(SDate) md,ProID from Stock group by ProID
  ) tempdt
  on tempdt.ProID=Provider.ProID

8.显示今天生日的元老,即生日与今天月日相同
  select * from bbsusers where month(ubirthday)=month(getdate()) and day(ubirthday)=day(getdate())

9.select * from table with (nolock) http://www.cnblogs.com/xiaofei59/archive/2011/04/15/2017359.html

   要提升SQL的查询效能,一般来说大家会以建立索引(index)为第一考虑。其实除了index的建立之外,当我们在下SQL Command时,在语法中加一段WITH (NOLOCK)可以改善在线大量查询的环境中数据集被LOCK的现象藉此改善查询的效能。

不过有一点千万要注意的就是,WITH (NOLOCK)的SQL SELECT有可能会造成Dirty Read

    原文作者:事理
    原文地址: https://www.cnblogs.com/slyzly/articles/2603600.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞