DBMS(DataBase Management System,数据库管理系统)和数据库。平时谈到“数据库”可能有两种含义:MSSQLServer、Oracle等某种DBMS;存放一堆数据表的一个分类( Catalog )
1个对象A对应着1个对象B,1个对象B对应着1个对象A
关系可以存入A或B对象中(例如:国家规定的夫妻关系)
1个对象A对应着n个对象B,1个对象B对应着1个对象A
关系存入B对象中(学生和班级,一个班级可以有多个学生,但一个学生只许有一个班级)
1个对象A对应着n个对象B,1个对象B对应着m个对象A
关系存入新建的一个关系表中(学生和选课, 1个学生可以有多门选课,一门选课可以有多个学生)
MS SQLServer的每个数据库包含:
1个主数据文件(.mdf)必须
1个事务日志文件(.ldf)必须
可以包含:
任意多个次要数据文件(.ndf)
多个事务日志文件
文件组:可将多个数据文件逻辑的分到一组,方便日后管理维护(备份、将表建在指定的文件组上等等。)
SQL 语句 CREATE TABLE 用于创建数据表,其基本语法如下:
CREATE TABLE 表名
(
字段名 1 字段类型,
字段名 2 字段类型,
字段名 3 字段类型,
………………
约束定义 1,
约束定义 2,
………………
)
ALTER TABLE 待修改的表名 ADD 字段名 字段类型
ALTER TABLE 待修改的表名 DROP 待删除的字段名
update 表名 set 字段名称=值 where 字段名=值
主键就是数据行的唯一标识。不会重复的列才能当主键。一个表可以没有主键,但是会非常难以处理,因此没有特殊理由表都要设定主键
主键有两种选用策略:业务主键和逻辑主键。业务主键是使用有业务意义的字段做主键,比如身份证号、银行账号等;逻辑主键是使用没有任何业务意义的字段做主键,完全给程序看的,业务人员不会看的数据。因为很难保证业务主键不会重复(身份证号重复)、不会变化(帐号升位),因此推荐用逻辑主键。
1.主键的作用:唯一标识表中的一条记录。表通常具有包含唯一标识表中每一行的值的一列或一组列。这样的一列或多列称为表的主键 (PK),用于强制表的实体完整性。
2.选择多列同时作为一个主键→组合主键(复合主键).(一般不建议采用)
3.尽量选择单列作为主键:
FUsedYears INT,PRIMARY KEY (FNumber))
不允许某一列的值为空
NOT NULL ,FAge INT NOT NULL ,FFavorite VARCHAR(20),FPhoneNumber VARCHAR(20))
值不能重复
add constraint tb_supplier_u1
unique (supplier_id);
DROP CONSTRAINT constraint_name;
add constraint tb_products_u1
unique (product_id,product_name);
界面中不给值默认会赋一个值给它
INT,FISMaster VARCHAR(5) DEFAULT ‘NO’)
add constraint CK_stuAge check (stuAge between 15 and 40)
谁引用了谁,谁就是外键
数据类型的意义:
1>提高效率。(减少空间,提高访问效率,‘1234567’如果用字符串存储占7个字节,如果用整型则占4个字节。);
2>能对数据进行正确的计算1+1,如果是整型则为2,如果为字符串则为11.
char [ ( n ) ]
用来存储布尔类型的数据,其值只能是0,1
(
从 1753 年 1 月 1 日 到
9999 年 12 月 31 日的日期
时间数据,精确到百分之三秒
)
从 1900 年 1 月 1 日 到
2079 年 6 月 6 日的日期和
时间数据,精确到分钟
231 - 1 字节
虽然类型名为 image,但是并
不意味着只能保存图片二进制
数据,实际上它可以保存任何
二进制数据
go语句的作用:
向 SQL Server 实用工具发出一批 Transact-SQL 语句结束的信号。
将SQL语句分段执行。
GO 不是 Transact-SQL 语句;它是 sqlcmd 和 osql 实用工具以及 SQL Server Management Studio 代码编辑器识别的命令。
SQL Server 实用工具将 GO 解释为应该向 SQL Server 实例发送当前批 Transact-SQL 语句的信号。当前批语句由上一 GO 命令后输入的所有语句组成,如果是第一条 GO 命令,则由即席会话或脚本开始后输入的所有语句组成。
GO 命令和 Transact-SQL 语句不能在同一行中。但在 GO 命令行中可包含注释。
用户必须遵照使用批处理的规则。例如,在批处理中的第一条语句后执行任何存储过程必须包含 EXECUTE 关键字。局部(用户定义)变量的作用域限制在一个批处理中,不可在 GO 命令后引用。
Top 获取前几条数据,top一般都与order by连用
Distinct 去除重复数据
select distinct sName from student
select distinct sName,sAge from student
DISTINCT是对查询出的整个结果集进行数据重复处理的,而不是针对某一个列。
1.建表,带重复数据。演示distinct
2.通过alter table增加identity列,再演示distinct。alter table TT2 add autoId int identity(1,1)
3.演示查询除主键外的其他列重复数据。
5>…Select 5-1>选择列,5-2>distinct,7>top(应用top选项最后计算)
1>…From 表 Join 表 on
2>…Where 条件
3>…Group by 列
4>…Having 筛选条件
6>…Order by 列
对行进行筛选,返回bool类型的值,如果某行中的列数据满足条件,则加入结果集,否则不出现在结果集中
where sId>5(范围值)
between … and …表示在一个连续的范围内
sName,sAge,sSex
from student where sAge
between 20 and 30 and sSex
=’男’
用as来取,当然也可以省略
from UserInfo
select top 1 *
from StudentInfo
from StudentInfo
按总页数的百分比来确定所要显示的页码数
asc表示升序,desc表示降序,不写默认为升序
ORDER BY子句位于SELECT语句的末尾,它允许指定按照一个列或者多个列进行排序,还可以指定排序方式是升序(从小到大排列,ASC)还是降序(从大到小排列,DESC)。
按照年龄升序排序所有学生信息的列表: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,math DESC
Order by 语句一般要放到所有语句的后面,就是先让其他语句进行筛选,全部筛选完成后,最后排序一下。
(表中数据是集合,集合是没有顺序的。Order by 返回的数据是有顺序的,故此我们把order by 以后返回的数据集合叫“游标”。)
order by cid desc,sId asc
不在某个区间内
–where cid not in (1,3)
用于处理字符串类型的值,运算符包括:like % _ [] ^
%与_写在[]中表示本身的含义
在[]表示一个连续的范围可以使用-
^写在[]内部的开头,表示不使用内部的任何字符
都是针对字符串操作的
问题:查询所有姓张的同学
_ 、 % 、 [] 、 ^
^只有MSSQL Server支持,其他DBMS用not like
通配符 %多字符匹配的通配符,它匹配任意次数(零或多个)出现的任意字符
通配符_ 单字符匹配,它匹配单个出现的字符
[] 只匹配一个字符 并且这个字符必须是[]范围内的 [0-9] [a-z]
not与like一起使用:not like ….
要通配、%、[、^这些字符怎么办?[]、[%]、[ [ ]、^(不需要放到中括号里,因为^只有放到中括号中才认为是通配符)
where sName like ‘%三%’
查询姓名中包含三的所有行
where sName like ‘张%’
查询姓张的学生信息
where sPhone is not null
left outer join,两表中完全匹配的数据,左表中特有的数据
from ClassInfo as ci
left join StudentInfo as si on ci.cId=si.cid
right outer join,两表中完全匹配的数据,右表中特有的数据
from ClassInfo as ci
right join StudentInfo as si on ci.cId=si.cid
inner join,两表中完全匹配的数据
from StudentInfo as si
inner join ClassInfo as ci on si.cid=ci.cid
where ci.cTitle=’青龙’
完全外连接:full outer join,两表中完全匹配的数据,左表中特有的数据,右表中特有的数据
–联合查询
select sid from StudentInfo
–union–合并,排序,消除重复项
–union all–合并,不排序,不消除重复项
–except–差集
–intersect–交集
select cid from ClassInfo
说明:from关键字可以省略不写
通常实现:逻辑删除,物理删除
1.truncate语句非常高效。由于truncate操作采用按最小方式来记录日志,所以效率非常高。对于数百万条数据使用truncate删除只要几秒钟,而使用delete则可能耗费几小时。
• 2.truncate语句会把表中的自动编号重置为默认值。
• 3.truncate语句不触发delete触发器。
–1.delete
语句删除数据的时候,自动编号没有恢复到默认值。但是truancate语句重新设置了自动编号
–2.通过truncate语句删除表中的数据的时候,只能一次性都清空,不能根据条件来删除,而delete可以根据条件来删除。
–3.truncate语句清空表中的数据时,速度(性能)比delete语句快的多的多的多。
–4..truncate语句不触发delete触发器。
–创建数据库
create database 数据库名
on primary
(
name=’stuDB_data’, – 主数据文件的逻辑名称
filename=’D:\stuDB_data.mdf’, – 主数据文件的物理名称
size=5mb, –主数据文件的初始大小
maxsize=100mb, – 主数据文件增长的最大值
filegrowth=15%–主数据文件的增长率
)
log on
(
name=’stuDB_log’,
filename=’D:\stuDB_log.ldf’,
size=2mb,
filegrowth=1mb
)
对表中的数据分组后,会得到一个分组后的结果集,如何对该结果集在进行筛选?→ having
查询班级人数超过三个人的班级。(见备注1)
注意Having中不能使用未参与分组的列,Having不能替代where。作用不一样,Having是对组进行过滤。
Having 是Group By的条件对分组后的数据进行筛选(与Where类似,都是筛选,只不过having是用来筛选分组后的组的。)
在Where中不能使用聚合函数,必须使用Having,Having要位于Group By之后。
Having的使用几乎是与where一样的,也可以用in。
Having count(*) in (5,8,10)
聚合函数对一组值执行计算并返回单一的值
对行数据进行合并
sum,avg,count,max,min
一般是对数字类型的列进行操作
一条查询中可以同时写多个聚合函数,但是不能与普通列混写
聚合中的null问题:不参与计算
对列中的所有数字求和。
返回组中各值的平均值。空值将被忽略。
后面可能跟随
采用度量值源列中仅来自定义此单元的成员行以及这些成员后代的行中的最高值。
采用度量值源列中仅来自定义此单元的成员行以及这些成员后代的行中的最低值。
CAST ( expression AS data_type
[ (length ) ])
CONVERT ( data_type
[ ( length ) ] , expression [ , style ] )
LEN() :计算字符串长度(字符的个数。)
datalength();//计算字符串所占用的字节数,不属于字符串函数。
测试varchar变量与nvarchar变量存储字符串a的区别。见备注1.
LOWER() 、UPPER () :转小写、大写
LTRIM():字符串左侧的空格去掉
RTRIM () :字符串右侧的空格去掉
LTRIM(RTRIM(’ bb ‘))
LEFT()、RIGHT() 截取取字符串
SELECT LEFT(‘abcdefg’,2)
SUBSTRING(string,start_position,length),索引从1开始。
参数string为主字符串,start_position为子字符串在主字符串中的起始位置,length为子字符串的最大长度。SELECT SUBSTRING(‘abcdef111’,2,3)
尝试使用SQLServer的帮助。
GETDATE() :取得当前日期时间
DATEADD (datepart , number, date ),计算增加以后的日期。参数date为待计算的日期;参数number为增量;参数datepart为计量单位,可选值见备注。DATEADD(DAY, 3,date)为计算日期date的3天后的日期,而DATEADD(MONTH ,-8,date)为计算日期date的8个月之前的日期 。
(入职一年以上的员工发1000$),入职日期+1年<当前时间
Sql2005中只有DateTime类型,2008中有date、datetime、datetime2 等类型。
DATEDIFF ( datepart , startdate , enddate ) :计算两个日期之间的差额。 datepart 为计量单位,可取值参考DateAdd。
统计不同入学年数的学生个数:
select DateDiff(year,sInDate,getdate()),count(*) from student Group by DateDiff(year,sInDate,getdate())
DATEPART (datepart,date):返回一个日期的特定部分
Month()、year()、day()来代替。
统计学生的生日年份个数:
select DatePart(year,sBirthday),count(*)
from student
group by DatePart(year, sBirthday)
1990年出生的人的个数?
group by 列名1,列名2…
聚合函数一般结合分组使用,进行分组内的数据进行统计
根据指定列进行分组
分组后条件筛选:having …
GROUP BY子句必须放到WHERE语句的之后 ,Group By与Order By都是对筛选后的数据进行处理,而Where是用来筛选数据的。
没有出现在GROUP BY子句中的列是不能放到SELECT语句后的列名列表中的 (聚合函数中除外)
错误: select sClassId,count(sName),sAge from student group by sClassId
正确: select sClassId,count(sName),avg(sAge) from student group by sClassId
备注1:
select
tSClassId as 班级Id,
count(*) as 班级人数
from TblStudent
group by TSClassId
备注2:
select
tSClassId as 班级Id,
count(*) as 班级人数
from TblStudent
where tSGender=’男’
group by TSClassId
可以使用having子句限制返回的结果集。group by 子句可以将查询结果分组,并返回行的汇总信息. 按照group by 子句中指定的表达式的值分组查询结果。
–当在一个查询语句中使用group by语句的时候,
–在select 语句的选择列里面,只能包含group by 语句中出现的列,或者是聚合函数,
–不能包括其他列。
开窗函数:over()
将统计出来的数据分布到原表的每一行中
结合聚合函数、排名函数使用
集合运算符是对两个集合操作的,两个集合必须具有相同的列数,列具有相同的数据类型(至少能隐式转换的),最终输出的集合的列名由第一个集合的列名来确定。(可以用来连接多个结果)
联合(union)与连接(join)不一样
简单的结果集联合(老师、学生):
select tName,tSex from teacher union
select sName,sSex from student
基本的原则:每个结果集必须有相同的列数;每个结果集的列必须类型相容。
select tName,tSex,-1 from teacher union
select sName,sSex,sClassId from student
联合:将多个结果集合并成一个结果集。union(去除重复,相当于默认应用了distinct)、union all(保留所有结果,不去除重复)
常见应用:底部汇总。使用Union all
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
insert into Score(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同样会去除重复数据。
视图:就是一个select语句,写起来比较复杂,多次被使用,则可以将这个select语句存放到一个视图中。
好处。使用方便,安全,看不见表的名称,结构信息。
as
查询语句
集合的结果集被当作一个集合使用,所以是不应该有顺序的。
如果加入了top n则可以使用,这样返回的又是一个n项的无序集合,虽然看上去是有顺序的
不要通过视图进行增加、修改、删除,主要进行查询操作
create view Student_Score
as
select stu.sName,sub.sTitle,score.scoreValue
from ScoreInfo score
inner join SubjectInfo sub on sub.sId=score.subId
inner join StudentInfo stu on stu.sId=score.stuId
将一条查询语句嵌入到另一条查询语句中,这就查询就叫做子查询
where exists
(select * from ScoreInfo where ScoreInfo.stuId=StudentInfo.sid)
(select *,
ROW_NUMBER() over(order by sid desc) as rowIndex
from StudentInfo) as t1
where rowindex between 5 and 8
多与聚合函数同时使用
select … from 表1 where 字段 between 参数1 and 参数2
开窗函数:几个行作为一个区,就被称为一个窗,能够进行按行划区的函数就是开窗函数
排名函数:rank() over(order by 列名 desc),比row_number()函数更适合用于排名
over与聚合函数一起使用,但不要和group by 一组使用,否则会报错
没有分组的时候,就认为是将整个查询结果分成了一组
select *,sum(销售数量) from myOrders会报错
改为:select *,sum(销售数量) over from myOrders则不会报错,并且在最后一列显示求和结果
例:求每个销售员的销量:select *,sum(销售数量) over(partition by 销售员) from myOrders
声明变量:
DECLARE @namevalue varcher(8)
DECLARE @num int
变量赋值:
SET @namevalue =”100”
SET @num=100
或
SELECT @namevalue =”100”
SELECT @num=100
这些变量由系统维护,不需要我们管理,用于查看信息
@@version:查看版本信息
@@identity:查看当前的标识
@@servername:查看服务器名称
@@error:返回最后执行的一句代码的错误编号,如果没有出错返回0;如果被go中断,就不能用
@@rownumber:查看最后执行的一句代码的影响行数
declare @id int
set @id=10
if @id>5
begin
–满足条件时,执行如下代码
print ‘ok’
end
else
begin
–不满足条件时,执行如下代码
print ‘no’
end
在查询语句的select后面,可以进行选择判断的逻辑
语法1:判等
Case 列名
When … then …
When … then …
Else …
End as 列别名
语法2:判不等
Case
When 包含列名的逻辑表达式 then …
When … then …
else …
End as 列别名
–显示学生信息,性别以”男女”显示
select *,
case sGender when 1 then ‘男’
when 0 then ‘女’ end as 性别
from StudentInfo
–将学生分数显示成等级 >=90 优,>=80 良,>=60 中,其它 差
select *,
case
when scoreValue>=60 and scoreValue<80 then ‘中’
when scoreValue>=90 then ‘优’
when scoreValue>=80 then ‘良’
else ‘差’ end as 等级
from ScoreInfo
declare @id int
set @id=1
while @id<10
begin
print @id
set @id=@id+1
end
begin try
delete from ClassInfo
end try
begin catch
print @@error
end catch
保证一个多操作的事情全部完成,否则回到做之前的状态
begin try
begin tran–设置起始点开启事务
delete from UserInfo where UserId>5
delete from ClassInfo
commit tran–提交事务使事务成为数据库中永久的不可逆转的一部分
end try
begin catch
rollback tran–反悔啦,回滚事务
end catch
创建一个特定标记符,只允许部分回滚
防止其它人员的误操作,通常带有暂停功能
update UserInfo set UserName=’abc1’ where UserId=10
rollback tran
select * from SubjectInfo
非重复性读取
幻读
丢失更新
脏读: 一个事务读取的记录是另一个未完成的事务的一部分,那么就会产生脏读。
非重复性读取:一个事务中两次读取记录,而另一个事务在这期间改变了数据,就会发生非重复性读取
幻读:运行UPDATE语句同时有人执行了INSERT语句,
中华词典中的A,B,C…..我们通过它能快速访问数据。
CREATE [索引类型] INDEX 索引名称
ON 表名(列名)
WITH FILLFACTOR = 填充因子值0~100
GO
CREATE NONCLUSTERED INDEX IX_TEST_TNAME –创建一个非聚集索引
ON TEST(TNAME) –为TEST表的TNAME字段创建索引
WITH FILLFACTOR = 30 –填充因子为30%
GO
SELECT * FROM TEST(INDEX = IX_TEST_TNAME) WHERE TNAME = ‘A’ –指定按‘IX_TEST_TNAME’索引查询
只有表或视图的所有者才能为表创建索引。表或视图的所有者可以随时创建索引,无论表中是否有数据。可以通过指定限定的数据库名称,为另一个数据库中的表或视图创建索引。
CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
ON { table | view } ( column [ ASC | DESC ] [ ,…n ] )
[ WITH < index_option > [ ,…n] ]
[ ON filegroup ]
< index_option > ::=
{ PAD_INDEX |
FILLFACTOR = fillfactor |
IGNORE_DUP_KEY |
DROP_EXISTING |
STATISTICS_NORECOMPUTE |
SORT_IN_TEMPDB
}
ALTER INDEX { | ALL}
ON
如果指定DROP_EXISTING选项,那么如果之前已经存在同名索引将在构造新索引之前被删除。当和群集索引一起使用该选项时,这个选项比简单删除并重新创建现有的索引更加有效。如果重新创建与现有索引完全匹配的索引,那么SQL Server知道它不需要涉及非群集索引,然而为了适应不同的行位置,显式删除和创建将导致重新构建所有非群集索引两次。如果使用DROP_EXISTING改变索引的结构,那么NCI只被重新构建一次,而不是两次。
就是一个函数,用于存储一段处理代码
好处:
完成代码的封装,实现代码重用;
安全
方便应用程序与数据库间通信,不用传大量sql语句过程,而只用传一个存储过程名称过来,简单方便
系统存储过程(在界面中打开看一看)
create proc usp_test1
参数列表
as
自定义代码段
create proc usp_compute
@n1 int=10,--定义了默认值
@n2 int--没有定义默认值
as
begin
select @n1+@n2
--return @n1+n2--一般不写返回值,但是也可以用
end
调用:exec usp_compute 100,98
实现改变(增加、修改、删除)发生时引发代码执行的对象
CREATE TRIGGER 名称 ON 表名
触发器类型(AFTER或Instead of)
触发操作(INSERT或DELETE或UPDATE)
AS
BEGIN
SET NOCOUNT ON;–不返回受影响行数,可以得到自定义的返回结果
END
create trigger ClassInfo_Delete on classinfo
after delete
as
begin
set nocount on
insert into classtest(ctitle)
select ctitle from deleted
end
alter view ScoreInfoList
as
select scoreinfo.sid,scoreValue,
StudentInfo.sName,stuid,classinfo.cid,
SubjectInfo.sTitle,subid
from ScoreInfo
inner join StudentInfo on ScoreInfo.stuId=StudentInfo.sId
inner join SubjectInfo on SubjectInfo.sId=ScoreInfo.subId
inner join classinfo on classinfo.cid=studentinfo.cid