跳到主要内容

MSSQL部分

理论指导实验

`<>`代表必须有
`[]`代表可写可不写
`{}`代表可重复列表
`|`多选一

数据库的结构

至少 一个主文件 一个日志文件

  • 数据文件
    • 主文件:mdf后缀的文件
    • 附加文件:ndf ,但是不是必须的,就是数据存不下之后采用分布式存到其他地方,这个就是ndf
  • 事务日志文件 ldf后缀的文件:用来回溯,如果没有日志文件会无法恢复数据库数据,例如回滚(rollback)之类的操作都是依赖于该文件

文件都有个逻辑文件名(引用文件时,在SQL Server中使用的文件名称),就是自定义数据库显示的名称 物理文件名,用于存在磁盘的名称

同mysql一样,提供了一些自带的系统数据库

  • master 记录SQL Server系统的所有系统级信息,例如:登陆账户信息、链接服务器和系统配置设置、记录其他所有数据库的存在、数据文件的位置、SQL Server的初始化信息等。如果master数据库不可用,则无法启动SQL Server。
  • model 用作SQL Server实例上创建的所有数据库的模板。对model 数据库进行的修改(如数据库大小、排序规则、恢复模式和其他数据库选项)将应用于以后创建的所有数据库。在model数据库中创建一张表,则以后每次创建数据库的时候都会有默认的一张同样的表。
  • msdb 用于SQL Server代理计划警报和作业。数据库定时执行某些操作、数据库邮件等。
  • tempdb 一个工作空间,用于保存临时对象或中间结果集。一个全局资源,可供连接到 SQL Server 实例的所有用户使用。每次启动 SQL Server 时都会重新创建 tempdb.

SQL Server 管理套件(SSMS)

  • 红线错误:有可能是缓存问题(就是没有及时刷新导致的):这时按ctrl+shift+r清除缓存就好了

  • 迁移用户数据库 有两种方法:

    • 分离和加载数据库
    • 生成脚本

理论部分

笛卡尔积等于:行相乘,列相加 0

连接也称: Θ\Theta连接(比较运算符)

Θ\Theta连接 = (非等值连接/等值连接/自然连接)

度数:相等就是说列相同 可比:是指数据类型相同

所以就是先R*S得到广义笛卡尔积,再根据连接条件对积结果进行筛选

自然连接:就是在等值连接的基础上自动去重

T-SQL

创建数据库

官网说明: https://docs.microsoft.com/zh-cn/sql/t-sql/statements/create-database-transact-sql?view=sql-server-ver15

-- [ ] 表示可以省略,例如没有指定路径就会使用默认的路径

create database 数据库名称
[
-- ON [PRIMARY]是表示表是建立在主文件组上。PRIMARY表示主文件组。如果没有指定默认文件组,则主文件组是默认文件组,ON [PRIMARY]也可以省略掉了。
[on primary] --就是指定下面的数据为主文件组
-- filegroup 是用来指定文件组的
[filegroup 文件组名称]
(
name=数据文件逻辑名称,
filename='路径+数据文件名',
size=数据文件初始大小,
maxsize=数据文件最大容量,
filegrowth=数据文件自动增长容量
)
]

创建日志文件

-- 例
create database mydb
log on
(
name=文件逻辑名称,
filename='路径+日志文件名',
size=日志文件初始大小,
maxsize=日志文件最大容量,
filegrowth=日志文件自动增长容量
)
-- 一般是以 M 为单位

数据文件自动增长容量:数据库大小不够时自动扩容多大

文件组

数据放在表中 --> 表属于某个文件组 --> 文件组的实体是辅助数据库文件 --> 辅助数据库文件放在性能优化的磁盘分区

操作的顺序: 1、先定义文件组 2、指定哪些辅助数据库文件属于这个文件组 3、将表放入到文件组中

归根结底,文件组只是一个用于管理分配方便的逻辑物件,其实际意义就是将表指定到某个数据库文件中。

USE master
GO
create database db_Study
on primary --主文件组和主要数据文件(就是指定下面这个为主文件组)
(name='db_study_Primary',
filename='D:\study\db_study_pri.mdf'),
filegroup db_Study_filegroup1 --用户定义文件组1
(name='db_study_fg_data1',
filename='D:\study\db_study_fg_data1_1.ndf'),--次要数据文件1
(name='db_study_fg_data2' ,
filename='D:\study\db_study_fg_data2_2.ndf'),--次要数据文件2
filegroup db_Study_filegroup2
(name='db_study_fg_data3',
filename='D:\study\db_study_fg_data3_1.ndf')
log on
(name='db_study_log',
filename='D:\study\db_study.ldf')
go

约束

添加约束的时机

  • 创建表时
  • 修改表时

语法:

create table 表名(
字段名 字段类型 约束
)

常用约束

  1. not null:非空,用于保证该字段的值不能为空
  2. default:设置默认值 语法:字段名 varchar(255) default 默认值
  3. primary key:主键,唯一,用于保证该字段的值具有唯一性,并且非空
  4. unique:可以有多个,保证该字段具有唯一性(可以有一个null)
  5. foreign key:外键,用于限制两个表的关系,用于保证该字段的值必须来自于主键 语法:foreign key(字段名) references 表2(字段名)
  6. check:约束 CHECK 约束用于限制列中的值的范围。CHECK 约束可以应用于一个或者多个列,也可以将多个CHECK 约束应用于一个列。
    # 下面的 SQL 在 "Persons" 表创建时为 "Id_P" 列创建 CHECK 约束。CHECK 约束规定 "Id_P" 列必须只包含大于 0 的整数。
    CREATE TABLE Persons
    (
    Id_P int NOT NULL,
    LastName varchar(255) NOT NULL,
    FirstName varchar(255),
    Address varchar(255),
    City varchar(255),
    CHECK (Id_P>0)
    )

例:

CREATE TABLE Orders
(
字段名1 int NOT NULL,
字段名2 int NOT NULL UNIQUE,
字段名3 varchar(255) default 默认值,
字段名4 int,
PRIMARY KEY (字段名1),
FOREIGN KEY (字段名4) REFERENCES2(2的字段)
)

完整性的约束

实体完整性:通过主键PK体现此数据库要管理的对象 参照完整性:外键FK 用户自定义完整性:CHECK(约束) 业务需求:例如:age int 0~100

用小括号作表达式的构成 用中括号标明字段名称 用运算符连接构成表达式 例: ([Credits]>(0))

外键基表 外键所在的表 外键列 所在列 主/唯一键基表 指向的表 主/唯一键列 所在列

外键

创建一个外键,如下

book_id nchar(6) not null foreign key REFERENCES boos_tb(book_id),

自增长列

  • 标识列 又称为 自增长列 可以不用手动的插入值,系统提供默认的序列值 就一个: auto_increment 关键字

Example

CREATE TABLE animals (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (id)
);

语法:

create table 表名(
id int 约束 auto_increment
);

注:

  • 一个表只能有一个标识列
  • 标识列的类型只能是数值型

单表查询

  • 确定范围between and
  • 确定集合in
  • 字符匹配like %,_,escape转义字符 模糊查询
  • 空值null
  • 排序asc,desc
  • 聚合函数count,sum,avg,max,min,distinct 聚合函数不能出现在where中
  • 分组group by
  • 筛选having --难点 -- 聚合函数count,sum,avg,max,min,distinct 聚合函数不能出现在where中 -- 分组group by -- 筛选having

组查询

20200414185710 约束分列级约束/表级约束

列级约束:是指在列定义的给出的约束 表级约束:在列定义完后,在表层次进行定义 语法: 20200414194858

查询列也可以使用算术表达式 20200414195319

关系数据库 库及表的定义是根据需求来的,所以需求的可靠和调查需要花时间并多次审核通过,尽可能的在初期考虑更全面些。关系DB 非关系数据库:NOSQL

约束尽可能在列级定完,如果没办法在列级定义,则添加到表级约束(像联合主键就必须用表级别,但是能在列级别就尽量用列级)

单表查询: 选行:选择操作 选列:投影操作

去掉重复值 在查询列前面加上一个distinct

select distinctfrom

排序

select *
from course
where pcno is not null
-- 先升序后降序
order by cno asc,credits desc

查询前100条

SELECT TOP (1000) [book_id]
,[book_name]
,[author]
,[publication_date]
,[price]
,[printing_count]
FROM [bookstore].[dbo].[boos_tb]

查询条件

| 查询条件             | 谓词                                        |
| -------------------- | ------------------------------------------- |
| 比较 | =,>,<,>=,<=,!=,<>,!>,!<; NOT+上述比较运算符 |
| 确定范围 | BETWEEN AND,NOT BETWEEN AND |
| 确定集合 | IN,NOT IN |
| 字符匹配 | LIKE,NOT LIKE |
| 空值 | IS NULL,IS NOT NULL |
| 多重条件(逻辑运算) | AND,OR,NOT |
  1. 聚集函数 就是统计 为了进一步方便用户,增强检索功能,SQL提供了许多聚集函数,主要有:
| 语句                          | 效果                                   |
| ----------------------------- | -------------------------------------- |
| `COUNT(*)` | 统计元组个数 |
| `COUNT([DISTINCT|ALL]<列名>)` | 统计一列中值的个数 |
| `SUM([DISTINCT|ALL]<列名>)` | 计算一列值的总和(此列必须是数值型) |
| `AVG([DISTINCT|ALL]<列名>)` | 计算一列值的平均值(此列必须是数值型) |
| `MAX([DISTINCT|ALL]<列名>)` | 求一列值中的最大值 |
| `MIN([DISTINCT|ALL]<列名>)` | 求一列值中的最小值 |

DISTINCT去掉重复 分组函数必须

多表查询

内连接

什么时候用? 在多表中如果只保留有关联的数据,则用内连接

使用比较运算符进行表间的比较操作,查询与连接条件相匹配的数据。根据所使用的比较方式不同,内连接分为等值连接自然连接自连接三种。

内连接(INNER JOIN)有两种,显式的和隐式

隐式的内连接

没有INNER JOIN,形成的中间表为两个表的笛卡尔积

select * 
from student,sc
where student.Sno=sc.Sno

显示的内连接

(ANSI标准,以此标准为主,建议采用),一般称为内连接,有INNER JOIN,形成的中间表为两个表经过ON条件过滤后的笛卡尔积。

select * 
from student s
inner join sc
on s.Sno=sc.Sno

自连接

如果在一个连接查询中,设计到的两个表都是同一个表,这种查询称为自连接查询。 --c1、c2逻辑上是两张表,物理上是一张表

SELECT c1.Cno,c1.Cname,c1.Pcno,c2.Cname 先修课程名,c1.Credits,c1.term
FROM Course c1
left outer join Course c2
on c1.Pcno=c2.Cno

外连接

什么时候用? 如果期望保留某一张表的完整信息,其它没有关联的数据也呈现出来,则用外不联接。

Example:想查看所有学生的选修情况,没有选修的也打印出来

外连接不只是列出与连接条件相匹配的行,而是列出左表(左外连接时)、右表(右外连接时)或两个表(全外连接时)中所有符合搜索条件的数据行。外连接分为左外连接、右外链接、全外连接三种。

总之就是满足连接条件的,另一个表里

左外连接

(left [outer] join)

返回左表中的所有行,如果左表中行在右表中没有匹配行,则在相关联的结果集中右表的所选择字段均为NULL。

6188fea574c1b6b5fe274b1ecf120155

--所有学生的选修情况,包括没有选修的
SELECT s.*,c.cno 选修的课程编号,c.cname 选修的课程名,sc.Grade 成绩
FROM student s
left outer join sc
on s.Sno=sc.Sno
left outer join course c
on sc.cno=c.cno

总结

  • 内、外连接的区别 仅从定义上看,就可以清晰的分辨出了。

    内连接:指连接结果仅包含符合连接条件的行,参与连接的两个表都应该符合连接条件。也就是,返回2个表中完全符合条件 的记录,结果集中每个表的字段内容均来自各自的表。

    外连接:连接结果不仅包含符合连接条件的行,同时也包含自身不符合条件的行。包括左外连接、右外连接和全外连接。也就 是,返回2个表中完全符合条件的记录,再加上2个表中各自的记录,结果集中的字段只有一个表中有记录时,另一个表中的字 段均使用空值null填写。

子查询和表查询的优先级

子查询要建立临时表(临时表不用时要销毁),这个过程是要时间需要消耗资源,所以优先用表连接。(笛卡尔积不用创建临时表)

集合查询

联合查询

union关键字

<查询块>
union
<查询块>

例如查询计算机系的学生或性别为男的学生的信息

交查询

INTERSECT 关键字 例 查询既是计算机系又是男生的学生(用法同上)

视图

视图属于外模式

20200512191556

视图:若数据要频繁查询,且数据来源于多表,组织过程耗时,建议使用视图(就是提前把数据连接好),如果使用基本表则会在频繁的连接表处浪费性能。反之若一个查询过于简单,跟单表无异,不建议使用视图

Example:随时查询学生的选修情况,包括学生信息,课程形象,选修成绩

视图可以加快数据的查询速度,这句话对吗?为什么? -- 不对,因为视图只是对复杂的查询操作进行封装,把一些字段进行隐藏,视图并不会对查询速度有任何影响 对速度有影响的是索引

视图是从一个或几个基本表(或者视图)导出的表。它与基本表不同,是一个虚表

哪些视图不能更新?

  • 若视图是由两个以上基本表导出的,则此视图不允许更新
  • 若视图定义中含有GROUP BY 子句,则此视图不允许更新
  • 若视图定义中含有嵌套查询,并且内层查询的FROM子句涉及的表也是导出该视图的基本表,则此视图不允许更新
  • 一个不允许更新的视图上定义的视图也不允许更新
  • 若视图字段来自聚集函数,则此视图不允许更新

若对外模式隐藏部分数据或对数据进行适当组织,则可以使用视图 就是数据分级,每一级能看到的数据(使用 * 也只能看的部分数据)逐级递减

所以使用情况: 1.查询复杂 2.多表查询 3.隐藏数据

操作

创建一个视图

create view 视图名称 [(字段名,字段名,....)]
as 子查询
[where 筛选]

索引

索引的目的:提高查询效率

前言

注意:SSMS自带了数据库引擎优化顾问 (Tool那里) 简单的说就是根据sql语句自动创建索引 参考

以下参考

索引的分类

  1. 聚集索引(物理) 一个表中只能有一个聚集索引
  2. 非聚集索引(逻辑) 一个表中可以有多个非聚集索引
  3. 唯一索引

索引也不是没有缺点,会增加额外的存储空间。同时降低了增加新记录,修改,删除的效率 (因为每次变更都需要更新索引)

而且最好在创建表之后就创建索引,因为当表中存在数据后再建索引还需要对表中的数据进行排序

因为用到了读取的概念,所以这里也补下读取数据 预读取, 物理读取, 逻辑读取

  • SQL Server存取数据都是以页为单位 (每页总大小8kb)
  • 逻辑读取:从缓存中读取数据 (从内存上读取数据)
  • 物理读取:从磁盘中读取数据 (就是第一次还在磁盘上把数据读取到内存上)
  • 预读取:一种性能优化机制,在执行查询时先预测执行 查询计划 所需的数据和索引页,然后在查询实际使用这些页前将它们读入缓冲区高速缓存

聚簇索引和非聚簇索引有何区别,为什么每个表只能有一个聚簇索引? -- 聚集索引: 根据物理顺序进行排序 一般是主键(例如在mysql就无法显示创建) -- 非聚簇索引:他结构顺序与实际存放顺序不一定一致 -- 因为一个表中的记录只能以一种物理顺序存放,所以只能有一个聚集索引

建了索引后,在查询中用到这一列才能体现这个索引的好处

所以说:需要频繁的用到一个字段才需要建立索引

一般情况下,聚集索引都是创建表时自动创建的,因此只需要创建非聚集索引

聚集索引

定义:数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。

特点

  1. 表中的数据页会依照该索引的顺序来存放。即:表中的数据的物理存储顺序和排列顺序相同,可按表中的某一字段或多个字段来排序记录
  2. 每个数据库中的每个表只能有一个聚集索引。因为一个表中的记录只能以一种物理顺序存放
  3. 通常情况下是对一个表按照主码 (关键字) 建立聚集索引,也可以用其他字段建立聚集索引

总结:就是物理存储和逻辑存储相同

创建 注意:SQL Server和MySQL的方式不同

--以这个列来建立索引
create clustered index 索引名称 on(列名)

值得注意的是,最好还是在创建表的时候添加聚集索引,由于聚集索引的物理顺序上的特殊性,因此如果再在上面创建索引的时候会根据索引列的排序移动全部数据行上面的顺序,会非常地耗费时间以及性能。

非聚簇索引

由上上可知,就是逻辑存储与物理存储不同 非聚集索引。表数据存储顺序与索引顺序无关。对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,其行数量与数据表行数据量一致。

定义:该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引

其实按照定义,除了聚集索引以外的索引都是非聚集索引,只是人们想细分一下非聚集索引,分成普通索引,唯一索引,全文索引。如果非要把非聚集索引类比成现实生活中的东西,那么非聚集索引就像新华字典的偏旁字典,他结构顺序与实际存放顺序不一定一致

创建

--以这个列来建立索引
create NONCLUSTERED INDEX 索引名称 ON 表名(字段名)

删除索引

drop index 表名.索引名称

唯一索引

不允许两行具有相同的索引值(就是唯一,最好不为空),否则不能建立唯一的索引

CRUD

插入

若需要全字段插入,则可不列出字段列表 如果没有指定字段,则默认是表的字段顺序,如果指定了字段,则是按照指定的顺序插入

insert into course value(...)
  • 插入数据是插入一整行(多条同理),所以,那些非空字段必写,其他的列可以用null或不写
  • 不写的字段是null,不是0(包括数值型)
  • 唯一只能有一个null
  • 自增:auto increment 注意:浮点类型无法自增

删除

删除(delete)

delete 语法:

delete 
from 表名
where 筛选条件

多表删除

delete 需要删的表
from1
[join type] join2
on 连接条件
where 筛选条件

需要删的表:需要删除哪个表的内容这里就填哪个

清空 (truncate)

使用truncate语句 truncate是用来清空数据的,所以不支持where之类的 语法:

truncate table 表名

truncate的特点:

  • truncate删除效率高
  • 假如要删除表中的自增长列,如果使用delete删除再次插入数据还是从上次的断点开始,使用truncate删除后,再插入数据则是从1开始
  • truncate删除不能回滚,delete删除可以回滚

级联删除(cascade)

是在创建表时才用到的,一般是外键后面加上

在级联删除中,还删除其外键值引用删除的主键值的所有行。

语法: Foreign Key

(column[,...n])
references referenced_table_name[(ref_column[,...n])]
[on delete cascade]
[on update cascade]

注释: column:列名 referenced_table_name:外键参考的主键表名称 ref_name:外键要参考的表的主键列 on delete:删除级联 on update:更新级联 SQL级联删除——删除主表同时删除从表——同时删除具有主外键关系的表

create table a
(
id varchar(20) primary key,
password varchar(20) not null
)
create table b
(
id int identity(1,1) primary key,
name varchar(50) not null,
userId varchar(20),
foreign key (userId) references a(id) on delete cascade
)

表B创建了外码userId 对应A的主码ID,声明了级联删除 测试数据:

insert a values ('11','aaa')
insert a values('23','aaa')
insert b values('da','11')
insert b values('das','11')
insert b values('ww','23')

删除A表内id为‘11’的数据,发现B表内userId 为“11”也被数据库自动删除了,这就是级联删除 delete a where id='11'

关系数据库设计的过程

用户需求  需求分析 概念模式(E-R模型)  逻辑设计 逻辑模型(关系模型)  物理设计 数据库模式

  • 一般一个实体一个关系(关系的个数大于等于实体的个数)
  • 若实体间联系是1:1,则可以在两个实体任选一个,其主键放入另一个实体当外键
  • 若实体间联系是1:n,则将实体其主键放入n端实体当外键
  • 若实体间联系是m:n,则新构建一个关系模式,其属性为两端实体关键字加上联系的属性,而关键字为两端实体关键字的组合

数据库中的函数依赖、码和范式

参考-CSDN

主属性:表示在候选键中的属性; 超码:是指能够唯一标识一个元组的属性集; 候选码:能够唯一标识一个元组,且不含多属性;是最短的超码(候选码可以有多个) 主键:用户选作元组标识的候选键; 外键:本联系中不作为主键,单在其他关系中作为主键的属性或属性组。

函数依赖

X→Y,表示Y依赖于X; X→Y,且Y→X不成立,Y→Z,则X→Z,表示Z传递依赖于X。

补: R: 一个关系 U: 关系R中的所有属性 α,β: R的子集

平凡与非平凡

函数依赖 α-->β,当 α包含β 时是平凡的;否则是非平凡的

就是后面是前面找得到的,能直接从前面看出来的(如下)

name,branch --> name 平凡 name,branch --> manager 非平凡


部分依赖与完全依赖

部分函数依赖: 设X、Y是关系R的两个属性集合,存在X→Y,若X’是X的真子集,存在X’→Y,则称Y部分函数依赖于X。

举个例子:学生基本信息表R中(学号,身份证号,姓名)当然学号属性取值是唯一的,在R关系中,(学号,身份证号)->(姓名),(学号)->(姓名),(身份证号)->(姓名);所以姓名部分函数依赖与(学号,身份证号);

完全函数依赖: 设X、Y是关系R的两个属性集合,X’是X的真子集,存在X→Y,但对每一个X’都有X’!→Y,则称Y完全函数依赖于X。

例子:学生基本信息表R(学号,班级,姓名)假设不同的班级学号有相同的,班级内学号不能相同,在R关系中,(学号,班级)->(姓名),但是(学号)->(姓名)不成立,(班级)->(姓名)不成立,所以姓名完全函数依赖与(学号,班级);


传递依赖

X→Y,且Y→X不成立,Y→Z,则X→Z,表示Z传递依赖于X。

码和函数依赖

在关系R中 K是一个超码,当且仅当

  • K-->U(U是一个R中全部属性的集合)

K是一个候选码,当且仅当

  • K-->U且
  • 任何K的真子集K'都不满足:K'-->U
  • 候选码就是最简可以求得全集的

函数依赖集的闭包

F:FD的集合称为函数依赖集。 F闭包:由F中的所有FD可以推导出所有FD的集合,记为F+

例1,对于关系模式R(ABC),F={A→B,B→C},求F+

根据FD的定义,可推出F+={φ→φ,A→φ,A→A,A→B,A→C,A→AB,A→BC,A→ABC,…},共有43个FD。 其中,φ表示空属性集。

属性集的闭包

属性集闭包定义 : 对F,F+中所有X→A的A的集合称为X的闭包,记为X+。可以理解为X+表示所有X可以决定的属性。

属性集闭包的算法(递归):(输入α,输出α+) 开始:

// R{A,B,C,G,H,I}
// F={CG-->H,CG-->I,A-->B,A-->C,B-->H}

// 最开始令α+为初始的α集合
let α+ = α;
// 遍历α+集合
for(let i:α+){
if(i能在F中取得其他属性){
// α+ 集合是动态增长的
α+ 集合加上通过F取得属性
}
}

例如:

R{A,B,C,G,H,I}
F={CG-->H,CG-->I,A-->B,A-->C,B-->H}
用AG开始求
1. A-->C
2. A-->B
3. CG-->H
4. CG-->I
5. 所以就推得了(AG)+ = ABCGHI

同理可以求得AG是候选码 (因为它是最短的可以求得所有属性的超码)

例题2:

R (C, T, H, R, S)
F = {C-->T, HR-->C, HT-->R, HS-->R}



-- 问题1:求(HR) +?
用HR开始求
1. HR-->C
2. C-->T
3. HT-->R
5. 最终推得(HR)+ = CTHR

-- 问题2:HS是候选码么?
是,候选码的定义是“能够唯一标识一个元组,且不含多属性”


-- 问题3:CH → S成立么?
不成立。S不依赖其他属性

范式

(1)1NF:关系中的所以属性值都是不可分割的原子值; (2)2NF:如果关系是1NF,且每个非主属性都完全依赖于候选键; (3)3NF:如果关系是1NF,且每个非主属性都不传递依赖于候选键; (4)BCNF:如果关系是1NF,且每个属性都不传递依赖于候选键。

例:建立一个供应商数据库。 其中供应商表S (Sno,Sname,Zip,City) 分别表示: 供应商代码供应商名供应商所在城市的邮编供应商所在城市 其函数依赖为:Sno→(Sname,Zip,City),Zip→City。“供应商”表S属于2NF。

判断方法: (1)用有向图表示出关系中的函数依赖; tNQkOe.jpg (2)找到入度为0的属性Sno,遍历有向图,可知,可完全遍历关系中的所有属性,则Sno为该关系的候选键; (3)判断该关系属于第几范式:该关系中的所以属性都是原子值,且所以的而非主属性(Sname,Zip,City)都完全依赖于主属性Sno,则该关系符合2NF,Zip→City表明该关系中非主属性存在传递函数依赖,则不符合3NF。

存储过程和触发器

概述

存储过程和触发器的区别

  • 存储过程,你调用的时候才会执行
  • 触发器就是你设定了数据库里比如删除,修改,插入时,才会触发

触发器不同于存储过程,触发器主要是通过事件执行触发而被执行的,而存储过程可以通过存储过程名称名字而直接调用。当对某一表进行诸如UPDATE、INSERT、DELETE这些操作时,SQLSERVER就会自动执行触发器所定义的SQL语句,从而确保对数据的处理必须符合这些SQL语句所定义的规则。

存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。

存储过程的优点:

执行速度更快---因为存储过程是预编译过的 模块化程序设计—类似方法的复用 提高系统的安全性—防止SQL注入 减少网络流量—只需传输存储过程的名称即可

复用/安全/性能/流量

触发器是一种特殊类型的存储过程,它不同于我们前面介绍过的存储过程。触发器主要是通过事件进行触发而被执行的,而存储过程可以通过存储过程名字而被直接调用。当对某一表进行诸如Update、Insert、 Delete 这些操作时,SQL Server 就会自动执行触发器所定义的SQL 语句,从而确保对数据的处理必须符合由这些SQL 语句所定义的规则。

暂时总结:存储过程感觉有点像C语言里的函数,触发器 = 监听器?

存储过程

用户自定义存储过程:

除了使用系统存储过程外,用户还可以创建自己的存储过程。

常见存储过程的语法:

CREATE  PROCEDURE  存储过程名
@参数1 数据类型 = 默认值 OUTPUT,
@参数n 数据类型 = 默认值 OUTPUT
AS
BEGIN
SQL语句
END

参数说明:

参数可选 参数分为输入参数、输出参数 输入参数允许有默认值

如何执行存储过程

EXEC  过程名  [参数]

这里提示一点:如果存储过程存在输出参数,一定要写Exec

说了这么多,下面我们一起来写一个分页的存储过程

create proc GetPageList
@pageIndex int,--页码
@pageSize int,--页容量(每页显示几条记录)
@pageCount int output,--总页数
@rowCount float output--总行数
as
select * from
(
select ROW_NUMBER() over(order by studentNo) as num,* from Student
) as temp where num between (@pageIndex-1)*@pageSize+1 and @pageIndex*@pageSize
select @rowCount=COUNT(*) from Student
set @pageCount=ceiling(@rowCount/@pageSize)
declare @pageCount int,@rowCount int
exec GetpageList 2,5,@pageCount output,@rowCount output
select @pageCount
select @rowCount

操作用户

-- 创建一个用户,密码为123456
create user alsritter IDENTIFIED by '123456'

-- 修改密码(当前用户)
SET PASSWORD = PASSWORD('123456')

-- 修改密码(指定用户)
SET PASSWORD FOR alsritter = PASSWORD('123456')

-- 重命名
RENAME USER alsritter TO alsritter2

-- ALL授全部权限(库.表,所以*.*表示全部)
-- 虽然这个用户用户已经可以用来删库跑路了,但是这个特权用户还是与root用户不同,因为它无法给其他用户授权(GRANT)
GRANT ALL PRIVILEGES ON *.* TO alsritter
-- 所以如果再勾上GRANT权限就与root用户无差别了
GRANT ALL PRIVILEGES ON *.* TO alsritter WITH GRANT OPTION

-- 查询权限
SHOW GRANT FOR alsritter

-- 撤销权限 REVOKE 哪些权限,在哪个库和表(*.*),给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM alsritter

-- 删除用户
DROP USER alsritter

mssql的数据类型

--数值型

bit--整型,取值范围[0,1,null],用于存取布尔值

tinyint--整型,取值范围[0~256)

smallint--整型,取值范围[-32,768~32,767)

int--整型,取值范围[(-2,147,483,648~2,147,483,647)

decimal--精确数值型 ,示例:decimal(8,4); //共8位,小数点右4位

numeric--与decimal类似

smallmoney:--货币型

money:--货币型

float--近似数值型

real--近似数值型 real=double


--日期型

Smalldatetime:--日期时间型,表示从1900年1月1日到2079年6月6日间的日期和时间,精确到一分钟

datetime--日期时间型,从1753年1月1日到9999年12月31日间所有的日期和时间数据, 精确到三百分之一秒或3.33毫秒

cursor--特殊数据型,包含一个对游标的引用。用在存储过程中,创建表时不能用

timestamp--特殊数据型,用来创建一个数据库范围内的唯一数码, 一个表中只能有一个timestamp列,每次插入或修改一行时,timestamp列的值都会改变。

Uniqueidentifier:--特殊数据型,存储一个全局唯一标识符,即GUID

--字符型

--一般来说
--如果纯英文和数字,用char/varchar
--如果含有中文字符,nchar/nvarchar

char--字符型,存储指定长度的定长非统一编码型的数据,必须指定列宽,列宽最大为8000 个字符

varchar--字符型,存储非统一编码型字符数据,数据类型为变长,要指定该列的最大长度,存储的长度不是列长,而是数据的长度

text--字符型,存储大量的非统一编码型字符数据

nchar--统一编码字符型,存储定长统一编码字符型数据,能存储4000种字符,统一编码用双字节结构来存储每个字符

nvarchar:--统一编码字符型,用作变长的统一编码字符型数据

ntext:--统一编码字符型,用来存储大量的统一编码字符型数据

binary--二进制数据类型,存储可达8000 字节长的定长的二进制数据

varbinary--二进制数据类型,用来存储可达8000 字节长的变长的二进制数据

image:--二进制数据类型,用来存储变长的二进制数据

范例脚本

--创建一个叫bookstore库
create database bookstore
on primary --指定创建的数据为主文件组中
(name='bookstore',
filename='D:\zjl\bookstore.mdf')
log on --创建一个log文件
(
name='bookstore_log',
filename='D:\zjl\bookstore_log.ldf'
)
go

use bookstore
go
--创建图书表
create table boos_tb(
book_id nchar(6) primary key,
book_name nvarchar(30) not null,
author char(10) not null,
publication_date date,
price decimal(4,1) default 20
)
--创建书店表
create table boosstore_tb(
boosstore_id nchar(6) primary key,
boosstore_name nvarchar(30) not null,
phone char(8) unique,
boosstore_address varchar(40),
postal_code char(6)
)
--创建销售表
create table boosstore_sell_tb(
book_id nchar(6) not null foreign key REFERENCES boos_tb(book_id),
boosstore_id nchar(6) not null foreign key REFERENCES boosstore_tb(boosstore_id),
sell_date Smalldatetime not null,
sell_count int check(sell_count>=1),
primary key(book_id,boosstore_id,sell_date)
)

use bookstore
go
--第九题 添加印刷数量这个列
alter table boos_tb add printing_count int;
--第十题 为列添加约束printing_count >=100,注意要指明添加的是constraint,否则默认是添加列
alter table boos_tb add constraint printing_count check(printing_count >=100);
--第十一题 将邮政编码删除
--注意,此处不能直接使用 drop 关键字,因为会默认删除的是约束,所以需要指定删除的是列
alter table boosstore_tb drop column postal_code;
--第十二题 修改类型
alter table boosstore_sell_tb alter column sell_count int;