PS:对数据库进行一些危险操作,一定要先备份
一.数据库简介
1. DBMS(DataBaseManagement System,数据库管理系统)和数据库数据库Schema有两种含义,一种是概念上的Schema,指的是一组DDL语句集,该语句集完整地描述了数据库的结构。还有一种是物理上的Schema,指的是数据库中的一个名字空间,它包含一组表、视图和存储过程等命名对象 MSSQLServer、Oracle等某种DBMS;存放一堆数据表的一个分类( Catalog )
2.品牌:
不同品牌的DBMS有自己的不同的特点:
MYSQL(速度很快,适合对数据要求并不是十分严谨的地方,去掉了很多中小型企业中不常用的功能,php里面用),
MSSQLServer(与.net结合很好,只能运行在windows平台下,大数据量、大交易量表现并不十分好)
DB2(大型数据库)、Oracle(大型数据库),
Access(文件)、 SQLite(极其轻量级数据库)、Sybase等。对于开发人员来讲,大同小异
SQL(语言)<SQLServer()<MSSQLServer。
SQL是英文StructuredQuery Language的缩写,意思为结构化查询语言。
除了Access、SQLServerCE、SQLite等文件型数据库之外,大部分数据库都需要数据库服务器才能运行。学习、开发时是连接本机的数据库,上线运行时是数据库运行在单独的服务器
3. 名词解释:
数据库DataBase,不同类的数据应该放到不同的数据库中
1.便于对各个数据类别的进行个性化管理
2.避免命名冲突
3.安全性更高
Table(表):关系数据库中的关系指的就是表。
不同的货物要放到各自的货物架,将这种区域叫做“表”(Table)。不同的表根据放的数据不同进行空间的优化,找起来也方便。
列(Column)、字段(Field)、行(Row)元组
4.杂谈
1.数据库里面的数据--关系型的数据。
2.关系转对象,将数据库中的数据关系转为对象进行处理(面向对象编程)
3.“-- ”为注释标识符,相当于java中的“//”
二.主键与外键
1.英文名:Primary key(主键)
2.主键简介:主键就是数据行的唯一标识。不会重复的列才能当主键。一个表可以没有主键,但是会非常难以处理,因此没有特殊理由表都要设定主键
3.主键的方法:业务主键和逻辑主键和组合主键
- 业务主键是使用有业务意义的字段做主键,比如身份证号、银行账号等;
- 逻辑主键是使用没有任何业务意义的字段做主键,完全给程序看的,业务人员不会看的数据。因为很难保证业务主键不会重复(身份证号重复)、不会变化(帐号升位),因此推荐用逻辑主键。
- 组合主键,有多个数据组合而成的,几乎不用。
4.英文名: Foreign Key(外键)
5.外键简介:A主键表里面有一列内容为B主键表的主键。那么该A主键表的改行内容就叫做外键,A表就叫做外键表。
三.DataBase包含的文件
1. 必须包含
- 1个主数据文件(.mdf)必须。--后缀名必须记住
- 1个事务日志文件(.ldf)必须。
2. 可以包含:
- 任意多个次要数据文件(.ndf)
- 多个事务日志文件
四.DataBase的数据类型(使用时机)
1. bit数据类型在写程序的时候只能用1(true)或0(false)来表示,但是在设计器中只能用true或false单词来表示。设计器中bit写true和false,在sql代码中用1和0
2.创建表的数据类型:
- Char(若为10,则只能存10个,不够的话空格补齐)
- Nchar
- Varchar(可以0-10个英文,不会空格补齐(动态分配),不能10个汉字)
- Nvarchar(可以10个汉字可以10个英文)
- Varchar(max)
- Nvarchar(max)
- Text
- Ntext
- int(将该列设定为主键后,可以在属性中设置自动增长)
3.一些技巧
- 带var表示可变
- 不带var表四固定长度
- 带N为unicode字符
- 不带N为非unicode字符,
- 如果列数据项的大小一致,则使用 char。
- 如果列数据项的大小差异相当大,则使用 varchar。
- 如果列数据项大小相差很大,而且大小可能超过 8,000 字节,请使用 varchar(max)
- ps:1. Char(10),10表示10个字符。能存储10个ASCII字符和5个Unicode字符。长度为1-8000
- 存储10个ASCII字符,占10个字节
- 存储5个Unicode字符占10个字节
- 2.Nchar(10),能存储10个ASCII字符或10个Unicode字符。长度为1-4000
- 存储10个ASCII字符占20个字节
- 存储10个Unicode字符也占20个字节。
五.SQL语句(脚本或命令)
1. 简介:
- SQL 全名是结构化查询语言(Structured Query Language),是关系数据库管理系统的标准语言,所有的数据库都可以使用
- SQL语句是和DBMS“交谈”专用的语句,不同DBMS都认SQL语法
- Sql语句中字符串用单引号,没有字符,都是字符串,单等号(=),转意(’’’’)
- Sql语句中关键字大小写不敏感,字符串还是敏感的
- Sql语句中创建库,表,删除,几乎大多数功能都可以通过代码来完成
2.主要成分:
DDL(数据定义语言,建表、建库等语句。)、DML(数据操作语言)和DCL (数据库控制语言)
- DDL:(Create Table、DropTable、Alter Table等)//对表或是数据库进行操作
- DML:Select、Insert、Update、Delete//对数据进行操作
- DCL:GRANT 授权、REVOKE取消授权
3.分离后加载数据库后出错的原因:
- 1,版本不一样(导出sql脚本。数据还原与备份,数据导入导出。)鼠标右键任务生成脚本-----生成低版本的脚本,后面高级设置中版本和数据类型更改
- 2.拒绝访问修改权限--—235对本电脑上的SQL程序右击属性权限全部选定为对号即可
- 3.不能改名修改权限
- 4.系统错误。-------kanqingkuang
- 5.只读
- 6. 表创建完成后进行修改时可能会报错------工具选项designers 阻止保存创建要求重新勾 去掉
4.生成脚本
数据库→右键→任务→生成脚本
- 可选择生成什么样的脚本
- 选择生成的数据库版本
- 是否包含某些脚本等。
- 是否生成带数据的脚本(2005、2008都有该功能express没有。)
将脚本发送到对方,对方复制粘贴到编辑框运行即可
4.通过代码创建数据库
代码语言:javascript复制drop database MySchool—删除数据库
---------------------------------------------------------------
create database MySchool---创建数据库
on primary—创建主文件
(
--用“,”分隔语句最后一句不用写
--括号一定是圆括号
name='MySchool_data',--数据库名称—最好加上_data以便分别日志文件与主文件
fileName='d:MySchool_data.mdf',--物理文件名
size=5mb,--初始大小
maxSize=10mb,--最大大小
fileGrowth=15% --主文件增长率
)
log on—创建日志文件
(
name='MySchool_log',--日志文件名
fileName='d:MySchool_log.ldf',--日志物理文件名
maxSize=4mb,--最大大小
size=2mb,
fileGrowth=1mb
)
5.创建表(除了creat,select,insert into,也可以创建表,在表备份里面)
代码语言:javascript复制useMyDBTest -- 声明在哪个数据库中生成,一定要写或者在上方选择
create table Tstudent -- 创建一个Tstudent表
(
stuId int identity(1,1) primary key, -- 列名类型 自增 主键
stuName nvarchar(10), -- 列明 类型
stuGender bit not null -- 列明 类型 非空
)
6.向表中插入数据(bit类型代码添加时 只能输入0或1)
- 1. Insert into 表名(列名1,列名2)values(值1,值2)
- 2. Insert into 表名values(值1,值2)-- 若向所有的列插入数据,则可以省略列名
- 3. Insert into 表(列1) values(值1)—向指定列中添加数据,但须保证其余列可以为NULL才可。
- 4.插入多行数据
insert into Score1(studentId,english,math)
select 1,80,100 UNION all
select 1,80,100 union all
select 3,50,59 union ALL
select 4,66,89 UNION all
select 5,59,100
----全部为union all连接的语句进行添加,才不会删除重复项,若有一个不是union all ,则就会删除重复项
Insert into 表(列)----当多行添加时只写一行改行代码即可
select 值1,值2 union—---写列值
select 值1,值2—最后一--行不必加union
-----union连接的语句进行添加数据会将重复添加的数据删除
7.更新表中数据
1.更新一部分数据关键字where,数据间的‘,’别忘了(可以更新一些数据)
代码语言:javascript复制UPDATE food SET fdname='zhazhahza', fddsec ='可以' WHERE fdname='炸鸡'
update 表名 set 列1=值1,列2=值2 where 列名=值
2.更新一整列的数据
代码语言:javascript复制UPDATEfood SET fdname='zhazhahza', fddsec ='可以'
update 表名set 列1=值1,列2=值2
8.更新数据的注意与补充
1.用where语句表示只更新列名是值的行
注意SQL中等于判断用单个=,而不是==
2.Where中可以使用的其他逻辑运算符:(||)or、(&&)and、(!)not、<、>、>=、<=、 <>(或!=)等,,,例如:
代码语言:javascript复制update Student set sAge = sAge 1—所有人的年龄加1
update Student set sAge=30 where sName='华佗' orsAge<25
update TbStudent set tSGender=0;
not and or—优先级
用小括号可以改变优先级.
update TblStudent set tSAge=tSAge 1
Null代表不知道
UPDATE TblStudent set tsname=tsname '^-^'where tsage<20 and tsgender='男' UPDATE food SET fdname='jjj' '-' WHEREfdid>5
9.数据的删除操作
1. delete FROM student--删除表中所有数据 表还有(不常用)
代码语言:javascript复制drop TABLE student --删除该表格
delete FROM Department where deptid=1--根据条件删除某一条数据
truncate TABLE Department--删除数据表还有,但会重置id值(主键)再写入数据时会重排列主键—不能加where
2. truncate语句删除数据的优点
代码语言:javascript复制truncate语句非常高效。由于truncate操作采用按最小方式来记录日志,所以效率非常高。对于数百万条数据使用truncate删除只要几秒钟,而使用delete则可能耗费几小时。
truncate语句会把表中的自动编号重置为默认值。
truncate语句不触发delete触发器(触发器后期会讲)。
10,注意点
1.GO的作用
为分段的作用,点击执行后执行到Go的地方便会停下,再点击执行执行下一段
2.N的作用(必须大写)
插入数据时,在单引号钱加一个大写的N使插入的数据不会乱码
3.【】的作用
想用关键词作为普通此使用,加上【】即可,尽量不适用、
11.约束
1.简介
- 数据库约束是为了保证数据的完整性(正确性)而实现的一套机制
- 见文件Employee.sql
- 非空约束 不让改的时候就工具选项,干掉勾
- 主键约束(PK) primary key constraint 唯一且不为空
- 唯一约束 (UQ)unique constraint 唯一,允许为空,但只能出现一次
- 默认约束 (DF)default constraint 默认值
- 检查约束 (CK)check constraint 范围以及格式限制
- 外键约束 (FK)foreign key constraint 表关系
2.鼠标点点约束(最后要进行Ctrl S保存才可以)
- 1.主键约束(PK),选中表单击设计设为主键
- 2.非空约束,将null不选中即可
- 3.检查约束(CK),选定一行右击选择CHECK约束,添加一个,修改名字,写入一个表达式类len(DeptName)>3即该内容必须大于三个字
- 4.默认约束(DF),在设计页面中选定一行,在下方的属性列表里有一个默认值,输入即可。 //改名时名字要规范
- 5,唯一约束(UQ),选中一行,右击选择“索引键”,添加,是否唯一,改名字,选定需要约束哪一列。
- 6.外键约束(FK),(前提是必须有两个表,一个为外键表,一个为主键表。)选定其中一个表,右击,关系,添加,改名,表和列规范,选定主键表,选定主键行和外键行,关闭,保存。。约束后必须使外键和主键的值相同
- 7,视图中点开表,下一级就是。
第十五天
Ps:像in or and等词,几乎可以在任何地方使用,多注意
一.SQL语句之代码对列(非数据)的操作(关键词alter)
1.删除外键表和主键表时应先删除外检表再删除主键表才可。或者进行“级联“—打开其中一张表的设计—右击—关系—表设计器—INSERT与UPDATE规范—改为级联--即可
2.手动删除一列(删除Employees里面的empage列)
ALTERTABLE Employees DROP COLUMN empage
--关键词为alter(改变)和drop和column(列)
3.手动增加列
ALTER TABLE Employees ADD EmpAdr NVARCHAR(50),EmpAgeINT
--不加column关键词,增加多列用逗号隔开
4.手动修改列的数据类型
ALTER TABLE employees ALTER COLUMN empemail NVARCHAR(1000)
--需要column和两个alter关键词
二,SQL语句之通过代码添加约束
1.添加主键约束
ALTER TABLE employees ADD CONSTRAINTPK_EmpId PRIMARY KEY (EmpId)
--constraint关键词,primary key关键词(填写需要添加约束的列名)
2.添加非空约束
ALTER TABLEemployees ALTER COLUMN empname VARCHAR(50) NOT NULL
--alter column注意 修改的列后面必须加上数据类型
3.添加唯一约束
ALTER TABLE employees ADD CONSTRAINTUQ_EmpName UNIQUE (empname)
--和主键约束差不多,只需让unique替换下来即可
4.添加默认约束
ALTER TABLE employees ADD CONSTRAINTDF_EmpGender DEFAULT ('男')FOR empgender
--关键词default(默认的意思),(默认的数据)for 所要操作的列
5.添加检查约束
ALTERTABLE employees ADD CONSTRAINT CK_EmpAge CHECK (empage>0 AND empage<120)
--括号内写所需要遵从的表达式
6.添加外键约束
ALTERTABLE employees ADD CONSTRAINT FK_employees_department FOREIGN KEY(deptid) REFERENCESdepartment (depid)
--第一个()内写外键表的指定列名,第二个括号内写主键表的指定列名
三.SQL语句之准确查询语句的补充
PS:对于查询语句from后面跟一个结果集(要起一个临时表名),不是非要一个单一的表名
1.查询一个表中的所有数据
SELECT* FROM employees
--*代表所有的列,为了简化而已。
2.查询特定列的数据
SELECTEmpName,EmpAge FROM employees
--将*替换下来即可,中间用逗号隔开
3.添加别名查询某一列(为了让别人看的更方便)
SELECT EmpName AS 姓名,EmpAgeAS 年龄 FROM employees
--关键词as 后面的为别名,但不会修改表自身的列名
SELECT姓名=EmpName,年龄=EmpAge FROMemployees
--另一种方法
SELECT EmpName EmpAdr AS 信息 FROM employees
--将几列数据合为一列,以别名的方式显示出来,加号注意同类型才可加
4. 查询具有某种条件的方法
SELECT姓名=EmpName,年龄=EmpAge FROMemployees WHERE deptid=1
--关键词where 查询depid为一的人
5.between and语句的使用,在什么之间
SELECT *FROM tblstudent WHERE tsage BETWEEN20 AND 30
6.in的作用 or的意思
SELECT*FROM tblstudent WHERE tsid IN (10,11,12)
--查询tsid为10或12或11的数据
**SQL语句之模糊查询
1. 模糊查询关键字 like
2.通配符 _ 、 % 、 [] 、 ^
select * from TblStudent where tSName like '张%^'
select * from TblStudent where tSName like '张%' andLEN(tSName)=3
--^只有MSSQL Server支持,其他DBMS用not like。
select * from TblStudent where tSName like '张%'
--通配符 %多字符匹配的通配符,它匹配任意次数(零或多个)出现的任意字符
select * from TblStudent where tSName like '张__'
--通配符_ 单字符匹配,它匹配单个出现的字符,查询三个字的张姓人物
select * from TblStudent where tSName like '张[a-z]_'
select * from TblStudent where tSName like '张[0-9]_'
select * from TblStudent where tSName like '张[^0-9]_'
--[] 只匹配一个字符 并且这个字符必须是[]范围内的 [0-9] [a-z]
not与like一起使用:not like ….
3. 要通配_、%、[、^这些字符怎么办?[_]、[%]、[ [ ]、^(不需要放到中括号里,因为^只有放到中括号中才认为是通配符)
四.select补充
1.可直接计算
select 45*3 --执行后会显示结果
2.显示当前时间
SELECT getdate ()
3.print的用法 和select这两个用法相同,但select是以表格的形式来显示,而print是以消息的方式来显示
4. SELECT '姓名',EmpName FROMemployees
--“,“可以添加临时列,显示结果为两列一行
SELECT EmpName AS '姓名' FROM employees
--as可以添加临时行,显示为一列两行
--“ ”可以连接内容,不增加列与行—总结为三个小符号的不同
五.折行(当语句过长时)从关键字的地方折行
六.TOP,order by,Distinct,percent关键词的作用(查询)
1.TOP
查询前几条数据
SELECTTOP 3*FROM employees --查询前三行
2.order by
排序,默认为从小到大,ASC为从小到大,不必添加
SELECT TOP 3*FROM employees ORDER BY deptid ASC–一般和TOP配合使用
3.percent
百分比,小数就进一,不是四舍五入
SELECTTOP 3 PERCENT *FROM employees ORDER BY deptid DESC
--在TOP后面,,DESC为从大到小
4.distinct
去除重复的数据(可以是指定列的数据)
SELECT DISTINCT EmpName FROM employees
--去除EmpName列的重复数据
SELECT DISTINCT *FROM employees
DISTINCT是对查询出的整个结果集进行数据重复处理的,而不是针对某一个列。
七.SQL聚合函数(需要有后缀括号)
1.注意:聚合使用后一定要弄清楚是否有其他列,不然会产生不伦不类的表
2.MAX(最大值)、MIN(最小值)、AVG (平均值)、SUM (和)、COUNT(数量:记录的条数。)
聚合函数对null值不计算。
如果一行的数据都是null,count(*)包含对空值行、重复行的统计
3.代码:
SELECT COUNT(empName) FROM employees—名字的数目
SELECT COUNT(empName),empage FROMemployees—会报错,因为会产生畸形表
SELECT MAX(empage),MIN(empage)FROMemployees—最大最小值
八.SQL语句之空值(null)的处理
1. 说明:数据库中,一个列如果没有指定值,那么值就为null,数据库中的null表示“不知道”,而不是表示没有。因此select null 1结果是null,因为“不知道”加1的结果还是“不知道”。
2.错误举例
select * from score where english = null ;
select * from score where english != null ;
都没有任何返回结果,因为数据库也“不知道”
3.SQL中使用is null、is not null来进行空值判断:
select * from score where english is null ;
select * from score where english is not null
4.将null值替换为指定字符,,在下面有介绍搜“isnull”即可
九.SQL之数据排序(order by)
1.关键词(ORDER BY)子句位于SELECT语句的末尾,它允许指定按照一个列或者多个列进行排序,还可以指定排序方式是升序(从小到大排列,ASC)还是降序(从大到小排列,DESC)
2. Order by 语句一般要放到所有语句的后面,就是先让其他语句进行筛选,全部筛选完成后,最后排序一下。
3.表中数据是集合,集合是没有顺序的。Orderby 返回的数据是有顺序的,故此我们把order by 以后返回的数据集合叫“游标”
4.例如:
按照年龄升序排序所有学生信息的列表:
SELECT * FROM Student ORDER BY sAge ASC
按照英语成绩从大到小排序,如果英语成绩相同则按照数学成绩从大到小排序 :
SELECT * FROM Score ORDER BY english DESC,math DESC
ORDER BY子句要放到WHERE子句之后:
SELECT * FROM Score where english>=60 and math>=60 ORDER BY english DESC,mathDESC
按总分查询
SELECT 总分=tenglish tmathFROM tblscore ORDER BY 总分 DESC
十.SQL之数据分组(group by,where,having)
1. 在使用select查询的时候,有时需要对数据进行分组汇总(即:将现有的数据按照某列来汇总统计),这时就需要用到group by语句。select 语句中可以使用group by 子句将行划分成较小的组,然后,使用聚组函数返回每一个组的汇总信息。//分组一般都和聚合函数连用。
2.group by 语句作用的一列就相当于聚合函数的作用。
SELECT 班级ID=tsclassid,总人数=COUNT(*)FROM tblstudent GROUPBY tsclassid
--count(*)因为前面执行的语句,显示的为符合前面语句的数量,tsclassid相当于被聚合
SELECT 班级ID=tsclassid,总人数=COUNT(*)
FROM tblstudent
WHERE tsgender='男'
GROUP BY tsclassid
--上述为一个语句,添加了一个条件为男
3. GROUP BY子句必须放到WHERE语句的之后 ,Group By与Order By都是对筛选后的数据进行处理,而Where是用来筛选数据的
没有出现在GROUP BY子句中的列是不能放到SELECT语句后的列名列表中的 (聚合函数中除外)
错误: select sClassId,count(sName),sAge fromstudent group by sClassId
正确: select sClassId,count(sName),avg(sAge)from student group by sClassId
4.分组之后再进行筛选(having)
对表中的数据分组后,会得到一个分组后的结果集,对该结果集进行删选用having
SELECT 班级ID=tsclassid,总人数=COUNT(*)
FROM tblstudent
GROUP BY tsclassid
HAVING COUNT(*)>3—having后需写聚合表达式
5.where和having的区别
注意:Having中不能使用未参与分组的列,Having不能替代where。作用不一样,Having是对组进行过滤。
Having 是Group By的条件对分组后的数据进行筛选(与Where类似,都是筛选,只不过having是用来筛选分组后的组的。)
在Where中不能使用聚合函数,必须使用Having,Having要位于GroupBy之后。
Having的使用几乎是与where一样的,也可以用in。
Having count(*) in (5,8,10)
十一. SQL语句的执行顺序
1>…From 表
2>…Where 条件
3>…Group by 列
4>…Having 筛选条件
5>…Select 5-1>选择列,5-2>distinct,5-3>top(应用top选项最后计算)
6>…Order by 列
十二.SQL之类型转换函数
1.简介:CAST ( expressionAS data_type)//顺序和convert相反
CONVERT ( data_type, expression,[style])
Select ‘您的班级编号’ 1 错误这里 是数学运算符
2.代码:
SELECT '英语成绩为:' CAST(tenglishAS VARCHAR(20)) FROM tblscore
SELECT '英语成绩为:' CONVERT(VARCHAR(10),tenglish) FROM tblscore
3.对日期的转换
SELECT CONVERT(VARCHAR(50),GETDATE())—显示当前时间
SELECT CONVERT(VARCHAR(50),GETDATE(),120)
--第三个参数可以填特定的数字,将显示的时间格式转换
4.isnull()函数对null进行操作
--当为null时,执行这个函数
SELECT ISNULL(CAST(tenglish AS VARCHAR(50)),'缺考')FROM tblscore
--将前面的参数替换为后面的参数,必要时可以进行数据类型的转换
十三.联合结果集
1.上下联合之union(效率低,因为要去除重复)
1.简介:
集合运算符是对两个集合操作的,两个集合必须具有相同的列数,列具有相同的数据类型(至少能隐式转换的),最终输出的集合的列名由第一个集合的列名来确定。(可以用来连接多个结果)
2.基本原则:
每个结果集必须有相同的列数;每个结果集的列必须类型相容。
3. SELECT tsage,tsphone FROM tblstudent
UNION
SELECT tsid,CAST(tmath AS VARCHAR(20)) FROMtblscore
4. 将多个结果集合并成一个结果集。
union(默认去除重复,相当于默认应用了distinct)
2.上下联合之union all(效率高,不去出重复)
1.和uniom几乎相同
2.不同点
select tName,tSex from teacher union
select sName,sSex from student
--UNION合并两个查询结果集,并且将其中完全重复的数据行合并为一条
select tName,tSex from teacher union all
select sName,sSex from student
--Union因为要进行重复值扫描,所以效率低,因此如果不是确定要合并重复行,那么就用UNION ALL
十四.备份表格
1.无条件复制 并且表没事先建好
SELECT *INTO newTblscore FROM tblscore
--将tblscore全部复制到通过该语句新创建的表newTblscore里面
--通过这种方式复制,只能复制表中的数据,以及列的名字和数据类型。对于约束,不会复制过来。下同
2.有条件复制并且表没事先建好
SELECT*INTO newTblscore FROM tblscore WHERE 4>3
--若where后面的表达式成立,则复制全部的表
--若where后面的表不成立,则只复制表结构
--这样做可以只复制表结构,但效率并不高
SELECT TOP 0 *INTO new1tblscore FROMtblscore
--只复制表的结构的话,这个方法效率高,建议使用
3.表要事先建好
insertinto backupStudent select * from students
--backupstudent要事先建好
十五.字符串函数(不改变表的内容,只改变显示的内容) SELECT LEN('你好哈,我不好')
--len计算字符串的长度
--计算时不包含字符右边的(再往右无字符)空格
SELECT DATALENGTH('你好a')
--datalength计算字符串的字节
--计算时包含右面的空格
SELECT LOWER('AFASdf')
--lower大写转小写,小写不变
SELECT UPPER('asfWE')
--upper小写转大写,大写不变
PRINT LTRIM(' 哈哈 ')
SELECT LTRIM(' 哈哈 ')
--ltrim字符串左侧的空格去掉
--print以消息的形式显示
SELECT RTRIM(' 哈哈 ')
--rtrim字符串右侧的空格去掉
--配合使用和ltrim
PRINT LEFT ('你好哈',2)
--left从左侧开始留下两个字符,其余的切掉
SELECT RIGHT ('你好哈',2)
--right从右侧开始留下两个字符,其余的切掉
SELECT SUBSTRING(umsg,2,4) FROM t6
--substring显示从第二个字符开始到第三个字符
十六.日期函数(可精确到秒 操作)
1.非日期函数,添加的内容之对日期的转换
SELECT CONVERT(VARCHAR(50),GETDATE())—显示当前时间
SELECT CONVERT(VARCHAR(50),GETDATE(),120)
--第三个参数可以填特定的数字,将显示的时间格式转换
判断是否为本月的方法
WHERE datediff(month,[StartDateTime],'2010-07-1')= 0
2. SELECT GETDATE()
--获得当前时间
SELECT DATEADD (YEAR,10,GETDATE())
SELECT DATEADD (MONTH,-10,GETDATE())
SELECT DATEADD (hour ,10,GETDATE())
--dateadd将当前时间增加第一个参数指导的变量10
--会自动进位(按照时间规范)
--可为负
PRINT DATEDIFF (YEAR,'2013-12-03',GETDATE())
SELECT DATEDIFF (DAY,'2013-12-03',GETDATE())
--datediff计算第二个参数到第三个参数的时间差,可以用天,月,年,小时等形式表示
SELECT DATEPART(YEAR,GETDATE())
PRINT DATEPART(MONTH,GETDATE())
--datepart分开显示当前时间
SELECT DATEDIFF(YEAR,tsbirthday,GETDATE())FROMtblstudent
--例子。计算年龄
第十八天(最后部分)
一:Case函数(case,when,then,end)
1.
SELECT tsid AS 学号,
tEnglish AS 英语,--所要显示的列名,逗号不要忘了
等级=--新增临时列的名称
( --括号可以不加
CASE
WHEN tenglish>90 THEN 'A'--中间部分为条件,后面部分为满足条件后显示的内容
WHEN tenglish>80 THEN 'B'—then后面的数据类型要一致
WHEN tenglish>70 THEN 'C'—没有逗号分隔
WHEN tenglish IS NULL THEN '缺考'
ELSE 'D'
END --以此结束,case语句
)
FROM TblScore
2.
select studentId,成绩=
(
case
when english between 90 and 100 then 'A'—and表示区间
when english between 80 and 89 then 'B'
when english between 70 and 79 then 'C'
when english between 60 and 69 then 'D'
when english < 60 then 'E'
else '缺考'
end
)
from score
3.
SELECT
A=CASE
WHEN A>B THEN A ELSE B-----A的值大于B的值显示A的值,否则显示B的值
END ,--配套的case开头,end结束
B=CASE
WHEN B>C THEN B ELSE C-----case在一个Select语句中可以多次使用
END
FROM t8
4.
SELECT 商品名称,销售总额=sum(销售数量*销售价格),
等级=
CASE
WHEN sum(销售数量*销售价格)>10000 THEN '金牌'
WHEN sum(销售数量*销售价格) BETWEEN7000 AND 10000 THEN '银牌'
ELSE '铜牌'
END
FROM Myorders
GROUP BY 商品名称
ORDER BY 销售总额 DESC
第十九天
一:子查询
1.简介:把一个查询的结果在另一个查询中使用就叫子查询。(将一个查询语句做为一个结果集供其他SQL语句使用) 就像使用普通的表一样,被当作结果集的查询语句被称为子查询。所有可以使用表的地方几乎都可以使用子查询来代替。
2.分类:
独立子查询(子查询可以独立运行)
SELECT
总人数=(SELECTCOUNT(*)FROM tblstudent),
男同学=(SELECTCOUNT(*) FROM tblstudent WHERE tsgender='男'),
平均成绩=(SELECT AVG(tmath)FROM tblscore)—这个没有使用from
相关子查询(子查询中引用了父查询中的结果)
SELECT tsname FROM (SELECT tsname,tsid FROMtblstudent) AS tbl
SELECT * FROM (SELECT * FROM tblstudent WHEREtsgender='男') AS tbl WHERE tbl.tsage=29;
SELECT * FROM tblstudent
WHERE tsclassid
IN (SELECT tclassid FROM tblclass
WHERE tclassname='高一一班' OR tclassName='高二一班')
3.注意点:
所使用的结果集需要起别名(as xxx)
可以多个表一起使用
如果子查询是多行单列的子查询,这样的子查询的结果集其实是一个集合。可以使用in关键字代替=号
二:分页
1.原始版分页
SELECT TOP 6 * FROM customers--这是选择的地三页,一页6个数据
WHERE customerid NOT IN --一定要not in才可
(SELECT TOP (6*2) customerid FROM customers)--去除前两页的数据
ORDER BY customerid--以id来排列的
2.现代版分页
SELECT * FROM --不需要top6了,因为下方的between语句
(SELECT *,编号=ROW_NUMBER()OVER(ORDER BY customerid)
FROM customers) AS newcus--核心代码
WHERE newcus.编号 BETWEEN(3-1)*6 1 AND 3*6--第三页的数据,将3替换为一个参数即可
3.关键词:row_number(),over(),orderby(),as,.
三:over与rank语句和partition语句()
1.over简介:
Over()就是传说中的”开窗函数”,本身聚合函数只会计算一次,开窗以后就可以为每条记录都计算一次聚合了。
Over子句可以为每一行计算表达式而不是只为一行,并且over可以单独定义窗口中的排序方式,而不影响最终结果集。例如:select*,row_number() over(order by id asc) as hanghao from callrecords order by iddesc
在应用具体的聚合函数、排名函数前对行集的分区和排序。over子句,用于支持窗口的计算,所以一般与排名开窗函数、聚合开窗函数一起使用。
窗口是用户指定的一组行。开窗函数计算从窗口派生的结果集中各行的值。
以前使用聚合函数必须分组,即便没有group by 子句,也是默认将表中所有的数据分成了1组,来聚合。通过使用over子句可以在不分组的情况下实现聚合运算,在查询结果集中既包含基础行的数据也包含聚合函数的值。(可以把over()子句理解成是“后台运行的数据”,只是为了让聚合函数或者是排名函数“用一下”,并不影响实际显示的数据。在后台提供数据。)
2.over两种使用方法
(1).over子句与排名开窗函数(row_number())一起用,语法:over([partition by 列1] order by 列2)。必须有order by 子句
SELECT *FROM
(SELECT *,编号=ROW_NUMBER()OVER(ORDERBY customerid)
FROM customers )AS newcus----添加编号的方法
WHERE newcus.编号 BETWEEN(3-1)*5 1 AND 3*5
(2).over子句与聚合开窗函数(rank())一起用,语法:over([partition by 列1])不能使用order by子句了。
不能用order语句是说在整个语句的最后面,不是在括号里,因为在最后面使用时会将原本因为聚合开窗函数局部聚合的数据打乱。
SELECT *,排名=RANK()OVER(ORDERBY tmath)
FROM tblscore
//排名形式1,2,2,4,4,4,7,7,9
------------------------求百分比
SELECT *,销售价格=(销售数量*销售价格),
百分比=(销售价格*销售数量)*1.0/(SUM(销售价格*销售数量)OVER(partition BY 销售员))*100 FROM myorders
//灰色为一个整体执行,,红色字体为一部分执行
3.partition语句(聚合开窗函数)
selectid,商品名称,行号=ROW_NUMBER()
OVER(partition by 商品名称 order by id asc) from MyOrders
--通过商品名称将所有相同的商品先分为一组显示,然后再进行排序
四:表连接
1.关键:两个表需要有类似于主键与外键的连接,on为筛选器
2. 内连接(inner join),多表内连接。(只将on后面等于的数据,相等才会显示,比如id两个表的id值必须相同才会将其连接 并显示)
无论几张表连接,每次执行都是两张表进行连接
SELECTtblscore.tSId,tsname,tmath,tenglish FROM tblstudent—可以查询组合表里的任意东西
INNER JOIN --关键词
tblscore ON tblstudent.tSId=tblscore.tSId
WHERE tsage>20
--on为关键词 外键=主键
3. 外连接
左外联(left outer join)
SELECT * FROM tblstudent
LEFT JOIN
tblscore ON tblstudent.tsid=tblscore.tSId
右外联(right outer join)
SELECT * FROM tblstudent
RIGHT JOIN
tblscore ON tblstudent.tsid=tblscore.tSId
//不同点:左(右)外连是以左(右)表为基础,左(右)表有多少行,右(左)表就要有多少行,不够就显示null-----连接关键词左边的就是左表,右边为右表
4.例题:
(1) 查询所有学生(参加和未参加考试)的学生姓名、年龄、成绩,如果没有参加考试显示缺考,如果小于english&math60分显示不及格
SELECTtsname,
tsage,
tmath=(CASE WHEN tmath IS NULL THEN '缺考' ELSE CONVERT(VARCHAR(10),tmath) END ),--case语句要保持then后面的类型一致,所以需要转换
tenglish=(CASE WHEN tEnglish IS NULL THEN '缺考' ELSE CONVERT(VARCHAR(10),tEnglish) END ),
是否及格=(CASE WHEN tmath>60 AND tenglish>60THEN '及格'ELSE '不及格' END )
FROM tblstudent
LEFT JOIN tblscore ON tblstudent.tsid=tblscore.tsId--所有的人根据题意要左连
(2) 对一个表进行操作,将表中对应的省和市写三列对应起来
SELECT--将一个表添加两个别名进行操作
tb1.areaid,
tb1.areaname,
tb2.areaname
FROM tblarea AS tb1
INNER JOIN tblarea AS tb2
ON tb2.AreaId=tb1.AreaPId--将不同的id对应起来
五:视图(方便查询)
1.简介:
视图是一张虚拟表,它表示一张表的部分数据或多张表的综合数据,其结构和数据是建立在对表的查询基础上,以表为基础建立视图,建立后便会存在数据库里面
视图在操作上和数据表没有什么区别,但两者的差异是其本质是不同:数据表是实际存储记录的地方,然而视图并不保存任何记录。
相同的数据表,根据不同用户的不同需求,可以创建不同的视图(不同的查询语句)
视图的目的是方便查询,所以一般情况下不能对视图进行增删改
表里面 的内容改变,相对应的视图数据就会改变
多次使用复杂代码时,就创建一个视图,谨记!!!!
不建议修改视图,若需求改变,则最好重新建立一个视图
优点:
筛选表中的行降低数据库的复杂程度
防止未经许可的用户访问敏感数据
2. 简单SQL操作:(什么时候用什么时候添加即可)
--以tblstudent表创建视图,内部只包含名字和年龄,关键词as
CREATE VIEW vw_cwStudent
AS
SELECT tsname,tsage FROM tblstudent
--查询视图
SELECT * FROM vw_cwstudent
--使用视图数量
SELECT * FROM vw_cwStudent WHERE tsage>30—好处在于将代码简化
--删除视图,用于更改视图,先删除再更改
DROP VIEW vw_cwStudent
3.注意点:
创建视图时,不能使用order by排序,除非有指定的top语句
所有查询的列,必须有列名,且列名必须唯一
createview vw_name as 后不能跟begin end
六:变量
1.变量分类
局部变量:
局部变量必须以标记@作为前缀 ,如@Ageint
局部变量:先声明,再赋值
全局变量(系统变量):
全局变量必须以标记@@作为前缀,如@@version
全局变量由系统定义和维护,我们只能读取,不能修改全局变量的值
2.局部变量(可以修改和定义)
(1).关键词declare(声明),@,set
声明时,先写变量名,再写类型,与C#不太一样
(2).简单SQL语句:
--变量的声明
DECLARE @name VARCHAR(10) ,@id INT –声明多个 逗号分隔
--给变量赋初值
SET @name='洋样' –只能单个赋值
SELECT @name=tsname FROM tblstudent WHERE tsid=2--可以给多个变量赋值,逗号分隔
--查询变量
SELECT(print也可) @name—select能同时输出多个,print只能输出一个
--以上三种语句需要一起运行才可以
SELECT以表格的方式输出,可以同时输出多个变量
PRINT 以文本的方式输出,一次只能输出一个变量的值
//////////////////////
DECLARE @num int =10--声明加赋值
SELECT(set也可) @name='李阳'--重新给变量赋值
//////////////////
declare @age int
set @age=10
print @age--输出10
select @age 1--输出11
print @age--输出10
select @age=@age 1--输出10
print @age--输出11
/////////////////
declare @num int
select @num=tMath from TblScore--将最后一个值存放在num变量中
--SET @num=(select tMath from TblScore)--严禁set只能一个,而select查询出许多
select @num
3.全局变量
(1).只能读
(2).简单全局变量
--记录上一个执行的语句的错误信息,若无错(有错,但一行受影响其值也为0),则为0
PRINT @@error
--常用全局变量
@@ERROR | 最后一个T-SQL错误的错误号 |
---|---|
@@IDENTITY | 最后一次插入的标识值 |
@@LANGUAGE | 当前使用的语言的名称 |
@@MAX_CONNECTIONS | 可以创建的同时连接的最大数目 |
@@ROWCOUNT | 受上一个SQL语句影响的行数 |
@@SERVERNAME | 本地服务器的名称 |
@@TRANSCOUNT | 当前连接打开的事务数 |
@@VERSION | SQL Server的版本信息 |
七:if else语句和while循环(与begin和end配套)
1.i公式:
IF(条件表达式)
BEGIN --相当于C#里的{
语句1 ……
END--相当于C#里的}
ELSE
BEGIN
语句1
……
END
////////////////////
WHILE(条件表达式)
BEGIN --相当于C#里的{
语句
……
continue
BREAK
END--相当于C#里的}
2.简单例题:
--计算平均分数并输出,如果平均分数超过60分输出成绩最高的三个学生的成绩,否则输出后三名的学生(if else)
DECLARE@avgEnglish INT--声明局部变量用以存储平均值
--SELECT @avgEnglish=AVG(tenglish) FROMtblscore--用select进行赋值
SET @avgEnglish=(SELECT AVG(tenglish)FROMtblscore)--set的用法
IF(@avgEnglish>60)
BEGIN
SELECTTOP 3 * FROM tblscore ORDER BY tenglish DESC--select可以显示数据!!
END
ELSE
BEGIN
SELECTTOP 3 * FROM tblscore ORDER BY tenglish
END
--计算1-100数字的和(while)
DECLARE@sum INT=0,@i INT=0
WHILE(@i<=100)
BEGIN
SET @sum=@sum @i--要用set赋值才可
SET @i=@i 1
END
SELECT @sum
---求1-100奇数和
DECLARE @sum INT=0,@i INT =0
WHILE(@i<=100)
BEGIN
IF(@i%2!=0)
BEGIN
SET @sum=@sum @i
END
SET @i=@i 1
END
SELECT @sum
第二十天
一:事务
1.总:同生共死,将几个语句联系起来,一个未成功,则后面所有执行了的语句都回到执行前的状态。
2.简介:
指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)--也就是由多个sql语句组成,必须作为一个整体执行
这些sql语句作为一个整体一起向系统提交,要么都执行、要么都不执行
3.步骤:
开始事务:BEGIN TRANSACTION
事务提交:COMMIT TRANSACTION—都没错时,执行此语句
事务回滚:ROLLBACK TRANSACTION—有一个错误就会执行此语句,将执行后的改变全部复原
//判断是否出错的方法
全局变量@@ERROR;
@@ERROR只能判断当前一条T-SQL语句执行是否有错,为了判断事务中所有T-SQL语句是否有错,我们需要对错误进行累计;
4.四大属性:
原子性
事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
一致性
事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如B 树索引或双向链表)都必须是正确的。
隔离
由并发事务所作的修改必须与任何其他并发事务所作的修改隔离。事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。
持久性
事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。
5.简单代码:
BEGIN TRANSACTION --开始事务的标志
DECLARE @sumerror INT =0--定义一个变量存储错误信息
UPDATE bank SET balance=balance-1000 WHEREcid=0001
SET @sumerror=@sumerror @@error--存储错误信息
UPDATE bank SET balance=balance 1000 WHEREcid=0002
SET @sumerror=@sumerror @@error
IF(@sumerror>0)--判断
BEGIN
ROLLBACK TRANSACTION --事务回滚roll为滚动的意思
END
ELSE
BEGIN
COMMIT TRANSACTION --事务提交commit承诺保证的意思
END
6.补充:系统存在隐形事务,了解
二:存储过程(SQL语句里面的函数,调用,简化代码)
1.步骤:
- 创建-声明变量-as-begin-SQL语句-end
- 就像数据库中运行方法(类似于函数)
- 和C#里的方法一样,由存储过程名/存储过程参数组成/可以有返回结果。
- 前面学的if else/while/变量/insert/select 等,都可以在存储过程中使用
2.优点;
- 执行速度更快 – 在数据库中保存的存储过程语句都是编译过的
- 允许模块化程序设计 – 类似方法的复用
- 提高系统安全性 – 防止SQL注入
- 减少网络流通量 – 只要传输 存储过程的名称
3.两种:
系统存储过程
由系统定义,存放在master数据库中
名称以“sp_”开头或”xp_”开头,自定义的存储过程可以以usp_开头。
////上放的表格
说明 | |
---|---|
sp_databases | 列出服务器上的所有数据库。 |
sp_helpdb | 报告有关指定数据库或所有数据库的信息 |
sp_renamedb | 更改数据库的名称 |
sp_tables | 返回当前环境下可查询的对象的列表 |
sp_columns | 回某个表列的信息 |
sp_help | 查看某个表的所有信息 |
sp_helpconstraint | 查看某个表的约束 |
sp_helpindex | 查看某个表的索引 |
sp_stored_procedures | 列出当前环境中的所有存储过程。 |
sp_password | 添加或修改登录帐户的密码。 |
sp_helptext | 显示默认值、未加密的存储过程、用户定义的存储过程、触发器或视图的实际文本。显示原始代码 |
自定义存储过程
由用户在自己的数据库中创建的存储过程usp,自己定义最好加上usp前缀
4.调用参数的存储过程
(1)无参数的存储过程调用:
Exec usp_upGrade
(2)有参数的存储过程两种调用法:
EXEC usp_upGrade2 60,55 ---按次序
EXEC usp_upGrade2 @english=55,@math=60 --参数名
(3)参数有默认值时:
EXEC usp_upGrade2 --都用默认值
EXEC usp_upGrade2 1 --第一个用默认值
EXEC usp_upGrade2 1,5 --不用默认值
5.简单代码:
(1)简单操作
exec sp_databases--查看系统所有数据库
exec sp_helptext sp_databases--查看存储过程的代码
exec sp_helptext usp_计算和--查看自己定义存储过程的代码
exec usp_计算和 11,12--调用存储过程
调用的时候exec ..
(2)定义存储过程
--创建存储过程
create proc usp_ChengFaa --proc关键词
@num1 int=0,--多个变量必须用逗号隔开
@num2 int=0
as --as关键词
begin
select @num1*@num2
end
-----调用该存储过程
exec usp_ChengFaa 3,4
--存储过程之模糊查询
create proc usp_personCount1
@age int,--逗号
@name nvarchar(50),
@countSum int output--返回值,在下方用一个变量接收
as--关键词
begin
set @countSum=(select COUNT(*) fromTblStudent where tsname like @name '%' and tsage=@age)--用and连接不同形式语句
select * from TblStudent where tsname like@name '%' and tsage=@age
end
------调用
declare @cs int--因为使用赋值的形式,所以定义该变量为output修饰的赋值
exec usp_personCount @age=19,@name='张',@countSum=@cs output--调用时可以给变量赋值,但都要用=号。也可以直接写,像上方。
select @cs--output修饰的变量将值付给@cs变量
--存储过程之提高分数
create proc usp_UpScore
@passLine int,--逗号,及格线
@upScore int,--提升的分数
@pCount int output--提升的次数
as
begin
set @pCount=0
declare @numNow int=(select count(*)from tblscore)--班级总人数
declare @notNow int=(select count(*) fromtblscore where tenglish<@passline)--不及格总人数
while(@notNow>@numNow/2)--while语句判断
begin
update tblscore set tenglish=tenglish @upScore--加分就是更新数据
set @notNow=(select count(*) fromtblscore where tenglish<@passline)--重新计算不及格人数
set @pCount=@pCount 1
update tblscore set tenglish=200 wheretenglish>200--避免超过总分
end
end
--调用,非赋值方法
declare @newCount int=0
exec usp_UpScore 150,2,@newCount output
select @newCount
--存储过程之分页
create proc usp_paging
@page int=0,
@count int=0,
@sumPage int=0 output
as
begin
set @sumPage=ceiling((select count(*)fromtblstudent)*1.0/@count)--ceiling向高进位关键词,1.0001进为2
select * from
(select *,编号=row_number()over(order by tsname )from tblstudent)as tbl
where tbl.编号 between (@page-1)*@count 1and @page*@count
end
--调用
declare @newPage int
exec usp_paging 3,7,@newPage output
select @newPage
三:索引
1.简介:
(1)与之对应的为全表扫描,对数据进行检索(select)效率最差的是全表扫描,就是一条条的找。
(2) 如果没有目录,查汉语字典就要一页页的翻,而有了目录只要查询目录即可。为了提高检索的速度,可以为经常进行检索的列添加索引,相当于创建目录。
创建索引的方式,在表设计器中点击右键,选择“索引/键”→添加→在列中选择索引包含的列。
使用索引能提高查询效率,但是索引也是占据空间的,而且添加、更新、删除数据的时候也需要同步更新索引,因此会降低Insert、Update、Delete的速度。只在经常检索的字段上(Where)创建索引。
(*)即使创建了索引,仍然有可能全表扫描,比如like、函数、类型转换等。年龄索引,以姓名查看。
(3)形式:
索引
相当于字典中的目录
加快查询速度
在执行增删改的时候降低了速度
聚集索引
相当于字典中拼音目录
拼音目录的顺序和数据的顺序是一致的
一个表中只能有一个聚集索引。
索引的排序顺序与表中数据的物理存储位置是一致的,一般新建主键列后回自动生成一个聚集索引。
非聚集索引(逻辑上的排序。 )
一个表中可以有多个非聚集索引。
相当于字典中笔画目录
笔画目录的顺序和数据是无关的
四:触发器
1.简介:
触发器的作用:
自动化操作,减少了手动操作以及出错的几率。
触发器是一种特殊类型的存储过程,它不同于前面介绍过的一般的存储过程。【在SQL内部把触发器看做是存储过程但是不能传递参数】
一般的存储过程通过存储过程名称被直接调用,而触发器主要是通过事件进行触发而被执行。
触发器是一个功能强大的工具,在表中数据发生变化时自动强制执行。触发器可以用于SQL Server约束、默认值和规则的完整性检查,还可以完成难以用普通约束实现的复杂功能。
那究竟何为触发器?在SQL Server里面也就是对某一个表的一定的操作,触发某种条件,从而执行的一段程序。触发器是一个特殊的存储过程。
2.总:作用就是备份和特殊的存储过程
3.触发器使用的表inserted表和deleted表
(1)deleted表存放由于执行delete或update语句而要从表中删除的所有行。
在执行delete或update操作时,被删除的行从激活触发器的表中被移动(move)到deleted
表,这两个表不会有共同的行。 ----删除时会将删除的数据放在deleted表中,写触发器时,将数据从该表中提取出来,放入新表中。。。inserted表同
(2)inserted表存放由于执行insert或update语句而要向表中插入的所有行。
在执行insert或update事物时,新的行同时添加到激活触发器的表中和inserted表中,
inserted表的内容是激活触发器的表中新行的拷贝。
说明:update事务可以看作是先执行一个delete操作,再执行一个insert操作,旧的行首先被移动到deleted表,让后新行同时添加到激活触发器的表中和inserted表中。
4.种类:
After触发器:
在语句执行完毕之后触发
按语句触发,而不是所影响的行数,无论所影响为多少行,只触发一次。
只能建立在常规表上,不能建立在视图和临时表上。(*)
可以递归触发,最高可达32级。
update(列),在update语句触发时,判断某列是否被更新,返回布尔值。
介绍如何编写after触发器。
instead of触发器
用来替换原本的操作
不会递归触发
可以在约束被检查之前触发
可以建在表和视图上(*)
介绍如何编写instead of 触发器
5.简单语句:
--删除的触发器
select top 0 * into newtblscore fromtblscore--创建一个表结构
----
create trigger tr_deleteScore on tblscore--依据tblscore表创建一个触发器,关键词on
for delete --声明删除触发器
as--关键词
begin
insert into newtblscore select * from deleted--从deleted表中将数据插入到新建表中
end
--使用
delete from tblscore where tsid=7--删除一条数据
select * from newtblscore--查看是否成功
--插入的触发器
create trigger tr_Records
on Records
for insert
as
declare@type int,@money money,@id char(4)
select@type = rType,@money=rMoney,@id=userId from inserted
update bank set balance = balance @money*@type
where cId = @id
--当插入数据的时候就会引发触发器
insert into Records values(-1,10,'0002')
6.建议:
不要太耗时
避免复杂操作
注意对多行触发时的处理(游标)
五:游标(了解,效率低,不常用)
1.用处:SQL语句是把结果集作为一个整体(整个作为一个单元)来操作的,但有时候我们需要针对结果集中的每条记录(或某部分记录)进行特殊操作,这时就需要用到游标。
对于及其复杂的子查询,则相对游标性能可能会更高
2.基本语法
1.delcare 游标名 cursor[local | global][游标选项] for 查询语句
2.open 游标名
3.fetch [next] from 游标名 into @v1,@v2…
4.判断@@fetch_status状态,继续fetch
5.close 游标名 –关闭游标
6.deallocate 游标名 –删除游标中数据库中保存的数据结构(彻底释放资源)
3.基本原理(了解)
Local
局部游标(当前存储过程中或批处理等,类似于c#的局部变量)
Global
全局游标(相对于当前连接)
游标选项:
FAST_FORWARD:指定启用了性能优化的 FORWARD_ONLY、READ_ONLY 游标。只能使用fetch next
FORWARD_ONLY :只能向前检索数据。默认选项。
READ_ONLY:只能读取数据,不能修改。禁止通过该游标进行更新。在 UPDATE 或 DELETE 语句的 WHERECURRENT OF 子句中不能引用游标。
SCROLL:指定所有的提取选项(FIRST、LAST、PRIOR、NEXT、RELATIVE、ABSOLUTE)均可用。
STATIC:定义一个游标,以创建将由该游标使用的数据的临时复本。对游标的所有请求都从tempdb 中的这一临时表中得到应答;因此,在对该游标进行提取操作时返回的数据中不反映对基表所做的修改,并且该游标不允许修改。
KEYSET:指定当游标打开时,游标中行的成员身份和顺序已经固定。对行进行唯一标识的键集内置在tempdb 内一个称为 keyset 的表中。
DYNAMIC:定义一个游标,以反映在滚动游标时对结果集内的各行所做的所有数据更改。行的数据值、顺序和成员身份在每次提取时都会更改。动态游标不支持ABSOLUTE 提取选项。
SCROLL_LOCKS:指定通过游标进行的定位更新或删除保证会成功。将行读取到游标中以确保它们对随后的修改可用时,Microsoft SQL Server 将锁定这些行。如果还指定了 FAST_FORWARD,则不能指定SCROLL_LOCKS。
OPTIMISTIC:指定如果行自从被读入游标以来已得到更新,则通过游标进行的定位更新或定位删除不会成功。当将行读入游标时SQL Server 不会锁定行。相反,SQL Server 使用timestamp 列值的比较,或者如果表没有 timestamp 列,则使用校验和值,以确定将行读入游标后是否已修改该行。如果已修改该行,则尝试进行的定位更新或删除将失败。如果还指定了FAST_FORWARD,则不能指定 OPTIMISTIC。
TYPE_WARNING:指定如果游标从所请求的类型隐式转换为另一种类型,则向客户端发送警告消息。
===============================================================================================================================
Fetch的选项:
NEXT :返回下一条记录。紧跟当前行返回结果行,并且当前行递增为返回行。如果FETCH NEXT 为对游标的第一次提取操作,则返回结果集中的第一行。NEXT为默认的游标提取选项。
PRIOR:返回前一条记录。返回紧邻当前行前面的结果行,并且当前行递减为返回行。如果FETCH PRIOR 为对游标的第一次提取操作,则没有行返回并且游标置于第一行之前。
FIRST:返回第一条记录。
LAST:返回最后一条记录。
ABSOLUTE n :如果n为正数,则返回从第一行开始的行,如果为负数,则返回从最后一行开始的行。
RELATIVE n:相对于当前行移动,如果n为正数则向前移动,如果n为负数则向后移动。
===============
@@CURSOR_ROWS :返回最后一个游标中的数据的行。动态游标返回为-1
4.语句:
--声明游标 cursorfast_forward for后面为要做的事
declare cur_tblStudent cursor fast_forward forselect * from tblStudent
--打开游标
open cur_tblStudent
--向下移动foreach缩写
fetch next from cur_tblStudent
while (@@fetch_status=0)
begin
fetch next from cur_tblStudent
end
--关闭游标
close cur_tblStudent
--释放缓存
deallocate cur_tblStudent
--查询TblTeacher表中的数据,为每个老师增加工资。每个老师的工资增长数额不同,具体增加额度在TblTeacherSalary表中
declare cur_TblTeacherSalary cursor forward_only
for
select tTId,reward from TblTeacherSalary
declare @teachId int
declare @treward money
open cur_TblTeacherSalary
fetch next from cur_TblTeacherSalary into@teachId,@treward
while @@fetch_status=0
begin--将查询的ttid,reward赋值给两个变量
update TblTeacher set tTSalary=tTSalary @trewardwhere ttid=@teachId
fetch next from cur_TblTeacherSalary into@teachId,@treward
end
close cur_TblTeacherSalary
deallocate cur_TblTeacherSalary
六:拾遗
1.动态SQL
String sql=“select * from @tbName”与string sql=“execute(‘select * from ’ @tbName)”;
尽量避免使用,会有安全问题(SQL注入),当遇到一些非常复杂的问题时自然会考虑到用动态sql,所以一般不用去主动考虑。
sp_executesql动态执行sql。(其实还是带参数的sql语句),exec(‘sql’)才是真正的动态sql。
2.跨数据库访问表
select * from [LYYSQLEXPRESS].Person.dbo.Employees
--select * from 【服务器名称】.数据库名称.表名
七:数据库的设计
1. 设计中的一些术语
实体,任何一个对象,表中的一行。
实体集,对象的集合,一张表。
属性,指实体的某个属性,即表的列。
联系(关系),实体与实体间的关系(主外键关系)
联系集(关系集),多个实体间的关系的集合,同类联系的集合。(存储关系的表,联想QQ好友关系表)
E-R图(实体-关系图),用图来描述表间关系的图。(用画图的方式来表示表和表之间的关系。)
映射基数:一个实体通过联系集能同时与多少个其他实体关联。假设有实体集A,与实体集B。
一对一,A中的一个实体最多能与B中的一个实体对应,反之一样。
一对多,A中的一个实体能与B中的任意多个实体对应,B中的一个实体则最多只能与A中的一个实体对应。
多对一,A中一个实体至多能与B中的一个实体对应,B中的一个实体则能与A中的任意多个实体对应。
多对多,A中的一个实体能与B中的任意实体对应,反之一样。
码(主键,属性集),唯一标示一个实体。
2.设计中注意事项
数据库设计过程,一般对于小型应用,只要一个人对应用需求非常了解则可以设计数据库,包括表、属性、关系、约束等。但对于比较复杂的应用,则很难由一个人了解所有的数据需求,这时就要通过不断了解需求,通过E-R图与客户反复确定需求并最终确定数据库设计。
数据库设计阶段一般只关心如何描述数据及其相互关系,不关心数据存储细节。
数据库设计中要避免的问题:
数据冗余,浪费存储空间等问题。
数据库设计不完整,比如,两种信息存储在了一个表中,没有关系表,会导致后续无法正常添加数据等各种问题。
3.设计过程一般包括
(1)需求分析 分析客户的业务需求.
(2)概要设计 根据需求分析阶段的数据画E-R图,通过E-R图和用户沟通,如此反复最终确定实际需求。
(3)详细设计 将E-R图转换为表,并使用三大范式审核。
(4)物理设计 选择合适的数据库, 进行物理实现:建库、建表、加约束等。
(5)实施与维护
4.技巧;
1对多时候,需要在N方加入外键。在学生表中增加“班级”中的关键字“班号”作为外部关键字
当多对多关系时,需要把关系也创建成一个表
5.数据库设计(审核)三大范式(3nf)
(1)第一大范式
第一范式的目标是确保每列的原子性(不可再分性)
如果每列都是不可再分的最小数据单元(也称为最小的原子单元),则满足第一范式(1NF)
数据冗余2nf(数据是否有冗余)
列没依赖主键
例如,如果关于员工的关系中有一个工资属性,而工资又由更基本的两个数据项基本工资和岗位工资组成,则这个员工的关系模式就不满足1NF。员工表(员工号,姓名,工资)进行分解,使其满足1NF条件。
员工表(员工号,姓名,基本工资,岗位工资)
(2)第二大范式
如果一个关系满足1NF,并且除了主键以外的其他列,都依赖与该主键,则满足第二范式(2NF),一个表只描述一件事情。
第二范式要求每个表只描述一件事情
(3)第三大范式
如果一个关系满足2NF,并且除了主键以外的其他列都不传递依赖于主键列,则满足第三范式(3NF)
第三范式要求其它列必须直接依赖于主键
(4)作用:
使用三大范式减少了数据冗余,但是牺牲了查询性能
所以有时为了性能,需要做适当折中,适当牺牲规范化的要求,来提高数据库的性能。
数据库设计看似简单,甚至同时会有多种设计可供选择,但当有大量复杂实体时(比如,银行,电信,电厂等业务),并非一件简单的事情(同时要考虑数据存储以及之间的各种关系及扩展问题),所以还需要大家认真对待。
八:SQL面试题
--1.列出EMPLOYEES表中各部门的:部门编号,最高工资,最低工资
--2.列出EMPLOYEES表中各部门的:部门编号、部门名称、最高工资、最低工资
--3.列出EMPLOYEES表中各部门中'职员'(Employee_job为'职员')的:最低工资,最高工资和部门Id
--4.对于EMPLOYEES中最低工资小于1000的部门,列出EMPLOYEE_JOB为'职员'的:部门编号,最低工资,最高工资
--5.根据部门编号由高到低,工资由低到高,列出每个员工的姓名,部门号,工资
--6.列出'吴用'所在部门中每个员工的姓名与部门号
--7.列出每个员工的姓名,头衔,部门号,部门名
--8.列出EMPLOYEES中头衔为'职员'的员工的姓名,工作,部门号,部门名
--9.对于DEPARTMENTS表中,列出所有:部门名称,部门编号,以及该部门的:员工姓名与头衔
--10.列出工资高于本部门工资平均水平的员工的部门编号,姓名,工资,并且按部门编号排序。
--11.对于EMPLOYEES,列出各个部门中工资高于本部门平均水平的员工数和部门号,按部门号排序
--12.请找出部门中具有两人以上,员工工资大于所在部门平均工资的:部门的id与这些人的人数。
--分解:
--1>.部门中有人的工资比部门的平均工资还高
--2>并且这些人在人以上
--3>查询出这些部门Id,与工资高于部门平均工资的人的人数。
--13.对于EMPLOYEES中低于自己工资至少5人的员工,列出其部门号,姓名,工资,以及工资少于自己的人数
-----------------------------答案------------------------------
表结构:
create database MyCompany
go
use MyCompany
go
create table Departments
(
Department_IDint identity(1,1) primary key,
Department_Namenvarchar(50),
)
go
create table Employees
(
Employee_Idint identity(1,1) primary key,
Employee_Namenvarchar(50),
Employee_Jobnvarchar(50),
Salarymoney,
Department_Idint foreign key references Departments(Department_ID)
)
Go
--------------------------------------------插入数据----------------------------------------------------------------------------------
----------------------------------部门表-------------------------------------------------------------------
SET IDENTITY_INSERT departments ON
insert departments(Department_ID,Department_Name)values( 1 , N'财务部' )
insert departments(Department_ID,Department_Name)values( 2 , N'行政部' )
insert departments(Department_ID,Department_Name)values( 3 , N'开发部' )
insert departments(Department_ID,Department_Name)values( 4 , N'市场部' )
SET IDENTITY_INSERT departments OFF
------------------------=============================员工表
SET IDENTITY_INSERT employees ON insert employees(Employee_Id,Employee_Name,Employee_Job,Salary,Department_Id)values( 1 , N'曹操' , N'组长' , 20000.00 , 1 )
insert employees(Employee_Id,Employee_Name,Employee_Job,Salary,Department_Id)values( 2 , N'刘备' , N'经' , 30000.00 , 3 )
insert employees(Employee_Id,Employee_Name,Employee_Job,Salary,Department_Id)values( 3 ,N'诸葛' , N'CEO' , 10000.00 , 2 )
SET IDENTITY_INSERT employees OFF
------------------------参考答案:-------------------------------------------------------
select * from departments
select * from Employees
--参考答案:
--1.列出EMPLOYEES表中各部门的:部门编号,最高工资,最低工资
select
department_id,
max(salary)最高工资,
min(salary)最低工资
from employees
group by department_id
--2.列出EMPLOYEES表中各部门的:部门编号、部门名称、最高工资、最低工资
select
emp.department_id,
dept.department_name,
max(salary)最高工资,
min(salary)最低工资
from employees as emp
inner join departments as dept on emp.department_id=dept.department_id
group by emp.department_id,dept.department_name
--3.列出EMPLOYEES表中各部门中'职员'(Employee_job为'职员')的:最低工资,最高工资和部门Id
select
department_id,
最高工资=max(salary),
最低工资=min(salary)
from Employees
where employee_job='职员'
group by department_id
--4.对于EMPLOYEES中最低工资小于的部门,列出EMPLOYEE_JOB为'职员'的:部门编号,最低工资,最高工资
--方案:
select
department_id,
min(salary)最低工资,
max(salary)最高工资
from employees
where employee_job='职员'
group by department_id
having min(salary)<1000
--方案:
select Department_Id,max(salary) 最高工资,min(salary) 最低工资 from dbo.Employees where Department_Idin
(select Department_Id from dbo.Employees groupby Department_Id having min(Salary)<1000)
group by Department_Id
--方案:
select
department_id,
max(salary)最高工资,
min(salary)最低工资
from dbo.Employees emp
where (select min(salary) from employees asemp_sub where emp_sub.department_id=emp.department_id)<1000
group by emp.department_id
--5.根据部门编号由高到低,工资由低到高,列出每个员工的姓名,部门号,工资
select employee_name,department_id,salary fromemployees order by department_id desc,salary asc
--6.列出'吴用'所在部门中每个员工的姓名与部门号
select employee_name,department_id from employees
where department_id in (select department_idfrom employees where employee_name='吴用')
--7.列出每个员工的姓名,头衔,部门号,部门名
select
emp.employee_name,
emp.employee_job,
emp.department_id,
dept.department_name
from employees as emp
inner join departments as dept on emp.department_id=dept.department_id
--8.列出EMPLOYEES中头衔为'职员'的员工的姓名,工作,部门号,部门名
select
emp.employee_name,
emp.employee_job,
emp.department_id,
dept.department_name
from employees as emp
inner join departments as dept on emp.department_id=dept.department_id
where emp.employee_job='职员'
--9.对于DEPARTMENTS表中,列出所有:部门名称,部门编号,以及该部门的:员工姓名与头衔
select
dept.department_name,
dept.department_id,
emp.employee_name,
emp.employee_job
from departments as dept
left join employees as emp on emp.department_id=dept.department_id
--10.列出工资高于本部门工资平均水平的员工的部门编号,姓名,工资,并且按部门编号排序。
--方案:
select * from employees as emp
inner join (select department_id,avg(salary)as avg_salary from employees group by department_id) as tmpdata
on emp.department_id=tmpdata.department_id
where emp.salary>tmpdata.avg_salary
--方案:(相关子查询)
select * from employees as emp
where
exists(
select department_id,avg(salary) as avg_salaryfrom employees as emp_sub group by department_id
having emp_sub.department_id=emp.department_idand emp.salary>avg(salary)
)
--方案:(相关子查询)
select
a.employee_id,
a.DEPARTMENT_IDas 部门号,
a.EMPLOYEE_NAMEas 姓名,
a.SALARYas 工资
from EMPLOYEES as a
where
a.SALARY >(select avg(SALARY) from EMPLOYEESas b where a.DEPARTMENT_ID = b.DEPARTMENT_ID)
order by a.DEPARTMENT_ID
--11.对于EMPLOYEES,列出各个部门中工资高于本部门平均水平的员工数和部门号,按部门号排序
select
emp.department_idas 部门编号,
count(*)as 员工数
from Employees as emp
where emp.salary > (select avg(salary) fromemployees emp_sub where emp_sub.department_id=emp.department_id)
group by emp.department_id
order by emp.department_id
--12.请找出部门中具有两人以上,员工工资大于所在部门平均工资的:部门的id与这些人的人数。
--分解:
--1>.部门中有人的工资比部门的平均工资还高
--2>并且这些人在人以上
--3>查询出这些部门Id,与工资高于部门平均工资的人的人数。
select
emp.department_idas 部门编号,
count(*)as 员工数
from Employees as emp
where emp.salary > (select avg(salary) fromemployees emp_sub where emp_sub.department_id=emp.department_id)
group by emp.department_id
having count(*) >2
order by emp.department_id
--13.对于EMPLOYEES中低于自己工资至少人的员工,列出其部门号,姓名,工资,以及工资少于自己的人数
--步骤:计算小于自己工资的人数的总和。
select
employee_name姓名,
salary工资,
小于自己工资的人数=(select count(*) from employees as emp_sub where emp_sub.salary<emp.salary)
from employees as emp
--步骤:筛选出工资比自己低的人数中小于的
select
employee_name姓名,
salary工资,
小于自己工资的人数=(select count(*) from employees as emp_sub where emp_sub.salary<emp.salary)
from employees as emp
where (select count(*) from employees as emp_subwhere emp_sub.salary<emp.salary)<5