SQL:Structured Query Language(结构化查询语言);数据库
主属性:包含于候选码的一个属性;好比若是候选码为AB,则主属性能够是A,B,只要包含于候选码的单个属性便可;
数据结构
SQL是专门用于关系模式的查询语言,他是高度抽象化的;函数
SQL的版本有最先的 ANSI SQL-->SQL92-->SQL99-->SQL2003oop
如今的各大商业数据库都是有各自版本的SQL,好比SQL Server对应T-SQL,而Oracle对应PL/SQL;性能
SQL中存在DDL和DML;spa
SQL默认是基于包的数据库,即容许一个表中存在重复的元组;设计
SQL不区分大小写,包括关键字,表名,属性名等都是,可是字符串是大小写敏感的;好比:FROM 和 from是同样的,代表Table和tablE是同样的,属性名Attr和attR是同样的;3d
SQL中的比较运算符:须要注意的是两个运算符,=和<>分别表示相等和不等,不能使用!=来表示不等;component
字符串链接运算符:+,即'xiaz'+'dong';orm
字符串是用单引号括起来的;
(1)CREATE TABLE建立表模式;
(2)ALTER TABLE 修改表模式,好比:
ALTER TABLE t1 ADD age int;
ALTER TABLE t1 DROP age;
(3)DROP TABLE 删除表模式,好比:
DROP TABLE t1;
小知识点:若是想要为某个属性定义默认值,能够在属性声明后面加上 DEFAULT 值;
好比:age int DEFAULT 0;
(1) INT;
(2)DECIMAL,指定小数点位数,DECIMAL(n,d) 表示一共n位有效数字,d个小数位;
(3)VARCHAR;变长的字符串,好比VARCHAR(5)表示最多长度为5的字符串;
(4)CHAR:固定长度的字符串,好比 CHAR(5)表示长度为5的字符串;
(5)DATE,DATE'2010-02-03'
(6)TIME:时间,由时、分、秒、微秒组成,TIME '14:00:20' 表示 14时00分20秒;
(7)TIMESTAMP:由DATE和TIME组成;
(5)BOOLEAN:TRUE、FALSE、UNKNOWN;
(6)位串BIT;B'0010'
答:以下图所示: 虽然这两种数据类型的存储方式不一样,可是若是char(3)类型的'a'和varchar(3)类型的'a'是相等的;
注意:SQL中string是用单引号括起来的;
答:数据库中含有多个表,不能单纯的建立表;
答:PRIMARY KEY 和UNIQUE都表示属性可以区别全部元组,可是PRIMARY KEY 不能存在NULL值,而UNIQUE容许NULL值;
答:能够声明在两个地方,
CREATE TABLE person(
id INT PRIMARY KEY,
name VARCHAR(20),
ismale boolean DEFAULT TRUE,
birth DATE,
salary DECIMAL(6,2)
);
或者
CREATE TABLE person(
id INT,
name VARCHAR(20),
ismale boolean DEFAULT TRUE,
birth DATE,
salary DECIMAL(6,2),
PRIMARY KEY(id)
);
示例:
原始Person表有以下数据:
规范:
SELECT attr1,attr2....attrn
FROM table1
WHERE predicate;
执行顺序:先FROM,再where后SELECT;
AS 可用来重命名属性或关系,好比:
SELECT id AS 学号,name AS 姓名,age AS 年龄,'ECNU' AS 学校 FROM Person |
运行结果以下所示:
从上图中能够看出,列被重命名,并且还多加了一个“学校”的属性,所以在SELECT 中能够用AS重命名,并且还能够添加新的列;
字符串的操做
1.字符串的链接:+
2.字符串的额比较:<,>,<>,=,<=,>=;
3.字符串的模式匹配:%和 _ 分别表示任意多个字符和单个任意字符;好比'xiazdong'匹配'xia%','xia_ _ _ _ _';
S LIKE P:S匹配模式P时返回true;
S NOT LIKE P: S不匹配模式P时返回true;
字符串中两个连续的单引号表示一个单引号,好比'a''a'表示字符串a'a;
咱们能够经过ESCAPE '字符'定义转义字符,好比ESCAPE '\'就表名定义\为转义字符,即\%表示真实的%,而不是模式匹配的%;
好比:name LIKE 'xia\%\_%' ESCAPE '\'表示\做为转义字符,而且名字是以xia%_开头的字符串;
举例:
若是Person表存在如下数据:
能够经过以下语句进行查找
SELECT *
FROM Person
WHERE name LIKE 'xia!%!_%' ESCAPE '!'
就能够查找到此记录;
SQL日期操做
SQL日期分为:
(1)DATE:由年月日组成,标准格式为'yyyy-MM-dd';
(2)TIME:由小时、分钟、秒组成,标准格式为'HH:mm:ss';
(3)TIMESTAMP:由DATE和TIME组合而成,标准的格式为'yyyy-MM-dd HH:mm:ss';
日期实例:
DATE '2012-04-25' 表示 2012年4月25日;
TIME '14:30:00' 表示14点30分00秒;
TIMESTAMP '2012-04-25 14:30:00' 表示2012年4月25日 14点30分00秒;
日期操做是能够经过通常的比较运算符进行比较的;
实例:
Person表结构以下所示:
CREATE TABLE `person` (
'id' int(20),
'name' varchar(20),
'age' varchar(20),
'birth' date,
'meeting' time,
'graduate' timestamp
PRIMARY KEY (`id`)
);
插入语句为:
INSERT INTO Person VALUES (10,'xiazdong-10',30,DATE'1991-12-10' , TIME'15:00:00',TIMESTAMP'2012-02-02 14:20:00' );
NULL操做
1.NULL值和任意值算术运算都是空值;
2. NULL值和任意值比较运算都是UNKNOWN值;
好比:
a=null,b=5,则a+b为null;
a=null,b=5,则a>5为UNKNOWN;
判断是否为NULL的语句为a IS NULL 或 a IS NOT NULL;
问:SELECT * FROM Person WHERE age>0 OR age<=0是否会返回所有的元组呢?
答:不会。由于若是age的值为null,则age>0为UNKNOWN,age<=0为UNKNOWN,则不返回;
排序操做
ORDER BY 属性 [asc\desc];
ORDER BY子句必定要放在全部语句的后面,即ORDER BY放在GROUP BY \HAVING等的后面;
举例:
对于Person表,以下语句:
SELECT * FROM PERSON
ORDER BY name,id DESC;
代表先以name值降序排列,当name值相等时而后以id值降序排列;
ORDER BY后面的属性能够是表达式,好比:
ORDER BY id+age,age+score;表示先以id+age的总数升序排序,若是id+age相等的话,则再以age+score升序排序;
不一样表的属性重名问题
好比:
在Person中Name和Course中Name属性不是一个含义,所以若是如下语句:
SELECT P.Name as stuName , C.Name as CourseName , C.teacherName
FROM Person as P,Course as C
WHERE P.name=C.stuName
为了区分不一样表的name属性,咱们须要在属性前面加上表的名称,而且还在SELECT 子句中重命名属性;
元组变量:像以上语句的Person as P ,其中P就是元组变量;
并、交、差运算
UNION || UNION ALL:对于集合操做的并;
INTERSECT|| INTERSECT ALL:集合的交;
EXCEPT || EXCEPT ALL:集合的差;
注意:
(1)好比UNION 后的关系须要去重复,由于是集合操做;而UNION ALL后的关系不须要去重复;
(2)须要保证集合操做的关系属性名要相等,不能出现好比:SELECT NAME FROM PERSON union SELECT AGE FROM PERSON;的状况;
举例:
(SELECT name FROM person)
UNION
(SELECT stuname AS name FROM course);
链接操做
1.交叉链接 CROSS JOIN
最基础的链接相似于直接用逗号分割,可是有一个区别:
A CROSS JOIN B :A不能等于B,即A和B不能是一张表;
A,B:没有以上限制;
2.天然链接 NATURAL JOIN
A NATURAL JOIN B:将A和B表中属性名相同的两列进行比较,若是值相等,则合并;
好比:
SELECT * FROM Person as A NATURAL JOIN Person as B;
3.θ链接 JOIN ON
A JOIN B ON predicate;
好比:
select * from person as B JOIN person as A ON A.id=B.id
4.外链接 OUTER JOIN
A [FULL | LEFT | RIGHT ] OUTER JOIN B;
A NATURAL LEFT OUTER JOIN B:在天然链接的基础上,保留A中不能匹配的元组,并将B中独有的属性处设为NULL;
举例:
子查询
子查询须要从里向外分析
1.子查询返回一个值
好比 select id from person where id =1 返回的只有一个值 1;
SELECT * FROM Person WHERE id = ( select id from Person WHERE id=1) ;
2.子查询返回一个关系
SELECT * FROM Person WHERE id IN (SELECT id FROM person) ;
2.1子查询位于WHERE中
SELECT * FROM PERSON WHERE ID > ALL (SELECT id FROM person);
2.2子查询位于FROM中
SELECT * FROM Person,(SELECT id FROM Person) AS P2;
消除重复操做
DISTINCT;
此符号能够放在SELECT后,也能够放在汇集操做之中;
好比:
SELECT DISTINCT person
FROM Person;
分组操做
GROUP BY 和 HAVING;
HAVING子句是对汇集操做符进行限制;
WHERE子句是对通常的属性进行限制;
好比
SELECT age,avg(score)
FROM Person
GROUP BY age
HAVING avg(score)>90
汇集操做
汇集操做忽略null值,好比age有1,2,null,则avg(age)=1.5;
SUM(a):对a求和;
SUM(DISTINCT a):在对a求和以前先去除重复;
AVG(a)
AVG(DISTINCT a):在对a求平均以前先去除重复;
MIN(a)
MIN(DISTINCT a):在对a求最小值以前先去除重复;
MAX(a)
MAX(DISTINCT a):在对a求最大值以前先去除重复;
COUNT(a):计算a属性的个数(不包括null的元组);
COUNT(DISTINCE a):在对a计数以前先去除重复;
COUNT(*):元组的个数(包括null元组);
补充:Top用法
Top是用来规定返回的元组数目;好比一个数据库表中包含1万个元组,目的是要返回前5个,则可使用Top;
在SQL Server中语法以下:
SELECT TOP 5 column1,column2.... //规定返回前5个元组,而且列出column1...属性;
FROM Table
好比:
SELECT TOP 5 age
FROM Person
ORDER BY age ; 表示列出年纪最小的5我的;
在MySQL中,语法以下:
SELECT *
FROM Table
LIMIT 5;
好比:
SELECT age
FROM Person
LIMIT 5
ORDER BY age; //列出年纪最小的5我的;
其余符号
EXISTS R:若是关系R非空时返回true;
NOT EXISTS R:若是R空,则返回true;
t IN R:若是元组t属于R中的某个元组,则返回true;
t NOT IN R:若是元组t不属于R中的任何一个值,则返回true;
c > ALL R:c值要大于全部R(只有一个列)的记录;
c < ALL R:c值要小于全部R的记录;
c<>ALL R:c不等于R中所有的记录;
c > ANY R:c大于R中一个记录便可;
c = ANY R:c等于R中任意一个记录便可;
c<>ANY R 和 c<>ALL R 的区别
c<>ANY R 表示R中存在一个元组,不等于c,就是说只要R中存在一个元组不等于c,就返回true;
c<>ALL R表示元组c不在R中;
SQL约束
主动元素:一个表达式或语句,编写后存储在数据库中,当某个特定的时间就会被执行;
好比约束、触发器等都是主动元素,由于好比约束的语句存储在数据库中,当插入或更新数据时被调用进行检查;
为约束命名
咱们能够形如:
CONSTRAINT [name] [约束]
好比:
CREATE TABLE Person(
id int CONSTRAINT c1 PRIMARY KEY,
name varchar(30)
);
键约束
PRIMARY KEY;
声明方式有两种:
(1)
CREATE TABLE Person(
id int PRIMARY KEY,
name varchar(30)
);
(2)
CREATE TABLE Person(
id int ,
name varchar(30),
PRIMARY KEY (id)
);
外键约束
一个关系中的某个属性为外键,则此属性中的值必须在另外一个关系中的主键或惟一性属性中出现;
(1)
CREATE TABLE Course(
id int REFERENCES Person (id), //引用Person表中的主键:id
name varchar(30)
);
(2)
CREATE TABLE Course(
id int ,
name varchar(30),
FOREIGN KEY (id) REFERENCES Person (id)
);
更新时违反外键约束时的动做设置
默认为拒绝此违反约束的操做;
就拿上面的例子讲,若是Course表中有一个元组的id属性为1,对应Person表的id=1,若是Person表的id从1更新为2,则级联修改,Course表的id也随着修改;
若是Course表中有一个元组的id属性为1,对应Person表的id=1,若是Person表的id=1的元组被删除,则Course表的对应元组置空;
咱们能够在声明时设置:
ON DELETE CASCADE:当Person的id删除时,Course对应的元组也会被删除;
ON DELETE SET NULL:当Person的id删除时,Course对应的元组会被设为null;
ON UPDATE SET NULL:当Person的id被更新,则Course对应的元组被设为null;
ON UPDATE CASCADE:当Person的id被更新,则Course对应的元组被更新;
(1)
CREATE TABLE Course(
id int REFERENCES Person (id)
ON DELETE SET NULL
ON UPDATE CASCADE, //引用Person表中的主键:id
name varchar(30)
);
推迟约束检查
若是要执行一个事务,而事务执行到一半时可能会违反某个预先设定的约束,可是最后事务提交时,是不违反约束的,(由于默认是执行一条语句检查一次)则可使用延迟检验;
这个功能MySQL没有提供延迟约束检查的机制;
每一个约束都会带有一个设置,能够是deferrable或not deferrable,分别表示可延迟和不可延迟:
(1)可延迟的意思是每次都在事务提交时才检查约束;
(2)不可延迟的意思是每条语句检查约束;
NOT DEFERRABLE 表示不可延迟,若是在声明时设置为不可延迟,则约束都是不可延迟的;
DEFERRABLE INITIALLY IMMEDIATE 表示不可延迟,可是和上面的NOT DEFERRABLE不一样,能够对约束进行更改,改成可延迟;
DEFERRABLE INITIALLY DEFERRED 表示可延迟约束;
问:NOT DEFERRABLE和DEFERRABLE INITIALLY IMMEDIATE 的区别
答:二者语义相同,可是区别在于一个能够对约束更改,一个不能够;
NOT DEFERRABLE只要一设定,就不能更改;
DEFERRABLE INITIALLY IMMEDIATE 能够对约束进行更改,改成可延迟,所以比较灵活,好比:
SET CONSTRAINT aa DEFERRED;//将immediate改成deferred;
SET CONSTRAINT aa IMMEDIATE;//将deferred改成immediate;
举例:
(1)
CREATE TABLE Course(
id int REFERENCES Person (id)
DEFERRABLE INITIALLY DEFERRED, //延迟约束检查;
name varchar(30)
);
(2)
SET CONSTRAINT [name] DEFERRED;
也能够将一个约束设置为延迟的;
非空约束
CREATE TABLE Course(
id int REFERENCES Person (id) NOT NULL, // id属性不为空
name varchar(30)
);
CHECK约束
CHECK约束是形如:
CHECK (age>30) 表示age属性药大于30;
CHECK约束括号中的语句能够是任何WHERE子句中的语句;
(1)基于元组的CHECK约束
当CHECK约束涉及此关系中的多个属性时,则使用基于元组的CHECK约束;
当元组被插入或更新时检查;
(2)基于属性的CHECK约束
此CHECK约束只属于一个属性,当属性被插入或更新时检查;
注意:
(1)CHECK对于旧的数据是不检查的,好比在设置CHECK约束前已经插入了违反CHECK约束的数据,则CHECK约束是检查不出的;
(2)基于元组的约束检查次数比基于属性的约束更多;
CREATE TABLE Person(
id int CHECK ( id > 0), //基于属性的约束
gender varchar(1) CHECK(gender in ('F','M')),
name varchar(30),
PRIMARY KEY (id),
);
CREATE TABLE Person(
id int ,
gender varchar(1),
name varchar(30),
PRIMARY KEY (id),
CHECK ( id > 0 AND CHECK(gender in ('F','M'))) //基于元组的约束
);
修改约束
添加约束
ALTER TABLE [表名] ADD CONSTRAINT [约束名] [约束];
ALTER TABLE person ADD CONSTRAINT c1 PRIMARY KEY (id);
删除约束
ALTER TABLE person DROP CONSTRAINT c1;
断言
CREATE ASSERTION ass1CHECK (判断语句);
DROP ASSERTION ass1;
断言相似于CHECK约束,可是又一个不一样点:
CHECK约束在删除时不作检查,而断言在任什么时候候都作检查;
好比:
CREATE ASSERTION a1 CHECK(10<=(SELECT sum(id) FROM Person)); //id的总和大于等于10;
ALTER TABLE Person ADD CONSTRAINT c1 CHECK(10<=(SELECT sum(id) FROM Person)) ;
若是如今有如下数据:
若是删除了id=10的数据,则CHECK约束是不会检查约束的,由于CHECK约束只会检查更新和插入;
而断言则会检查到不知足断言;
触发器
触发器简单地说就是:当遇到某个事件时,触发器被触发,并执行一系列动做;
触发器被称为事件-条件-动做规则(ECA规则),由于是因为某个事件(好比插入、删除、更新事件)的发生触发了触发器,而若是此事件使得条件(WHEN)为真,则执行动做(SQL),若是条件为假,则不执行动做;
MySQL也不支持标准的触发器语法,而是有本身的触发器语法!
咱们用例子来说解触发器的语法:
CREATE TRIGGER t1 //t1触发器
AFTER UPDATE OF id ON Person //在Person表的id被更新以后被触发,AFTER能够被改成BEFORE,UPDATE能够被改成INSERT DELETE,可是插入和删除不能使用“OF 属性”,只能是AFTER INSERT ON Person,AFTER UPDATE On Person,AFTER DELETE ON Person;
REFERENCING
OLD ROW AS old //旧元组,好比若是是更新,则old表示更新前的每行;
NEW ROW AS new //新元组,好比若是是更新,则new表示更新后的每行;
//能够加上
//OLD TABLE AS oldtable
//NEW TABLE AS newtable 若是是FOR EACH STATEMENT,则必须是OLD TABLE 和 NEW TABLE
FOR EACH ROW //对于每行,执行一次触发器,能够是FOR EACH STATEMENT,好比若是是更新语句触发器,则对于每一个更新语句,执行一次触发器;
WHEN (id>10) //条件,能够是where子句中的任何表达式,能够不加,不加则直接执行动做
BEGIN
UPDATE Person //动做
SET name= old.name
WHERE name=new.name;
END
注意点:
(1)
REFERENCING
OLD ROW AS old //旧元组
NEW ROW AS new //新元组
FOR EACH ROW //对于每行
是固定的,若是是FOR EACH STATEMENT,则不能使用:
REFERENCING
OLD ROW AS old
NEW ROW AS new
,可是可使用:
REFERENCING
OLD TABLE AS old
NEW TABLE AS new
FOR EACH STATEMENT
,表示对于每一个新、旧的表;
固然也能够同时引用这些,如:
REFERENCING
OLD TABLE AS oldtable
NEW TABLE AS newtable
OLD ROW AS oldrow //旧元组
NEW ROW AS newrow
FOR EACH ROW
(2)只有UPDATE可以针对某个属性的更新定义触发器,INSERT/DELETE只能针对某个元组定义触发器;
示例:
(1)
BEFORE INSERT ON Person
REFERENCING
OLD ROW AS oldrow
NEW ROW AS newrow
FOR EACH ROW
表示在插入语句执行以前触发,newrow表示将要插入的元组,而oldrow没有意义;
(2)
AFTER DELETE ON Person
REFERENCING
OLD ROW AS oldrow
NEW ROW AS newrow
FOR EACH ROW
表示在删除语句执行以后触发,oldrow表示要删除的元组,而newrow没意义;MySQL触发器语法
没有WHEN , REFERENCING,而old和new默认已经给定;
CREATE TRIGGER t1
BEFORE UPDATE ON Person
FOR EACH ROW
BEGIN
IF new.id>10 then
SET NEW.name='zzzz';
END IF;
END
视图
视图并非存储在数据库中的数据,而是由一个SQL语句构成;
CREATE VIEW viewname AS (SQL语句);
CREATE VIEW viewname(属性重命名) AS (SQL语句);
DROP VIEW viewname;
可更新视图:若是视图只涉及单个表,且知足其余一些必要条件时,才能对视图进行更新、插入、删除;
对视图的插入、删除、更新其实是对表的操做。
举例:
CREATE VIEW v1 AS(
SELECT id
FROM Person
WHERE id>5
);
针对视图的替换触发器
有一种专门针对视图的触发器,若是定义了此触发器,则对视图的插入、删除、更新语句将会被触发器定义的语句所替换;
语法:将BEFORE\AFTER换为INSTEAD OF;
好比:
INSTEAD OF UPDATE ON Viewname
.......
BEGIN
...... //触发器的更新语句将不会执行,而会执行此处的语句;
END
物化视图
和视图不一样,物化视图是真实地存储在数据库中的;
若是一个视图被频繁的访问到,则须要使用物化视图预先计算,减小重复计算量;
CREATE MATERIALIZED VIEW name AS (
SELECT name,avg(score)
FROM course,person
WHERE course.id=person.id
GROUP BY name
);
本来若是每次要查询每一个人的平均分,则须要计算上面的SQL语句,若是定义了物化视图,则只须要简单的查询便可;
物化视图的维护
(1)对于每一个更新语句都会增量式地更改物化视图;
好比Person(id,name,age);
物化视图SELECT id FROM Person;
当插入Person一个元组时,则不须要从新构造物化视图,只须要把新插入的id插入到物化视图中;
(2)天天某个时间点重构物化视图;
索引
针对某种状况加快查找速度;通常都是用B树或B+树实现;
CREATE INDEX indexNameONTable(attr1,attr2); //对attr1和attr2作索引
DROP INDEX indexName;
好比:
CREATE INDEX i1 ON Person(id,name);
SQL DML
INSERT INTO [Table][(属性)] VALUES(值):插入单个元组;
INSERT INTO Table [SQL语句]:批量插入;
DELETE FROM Table WHERE [...];
UPDATE Table SET [更新语句] WHERE [谓词];
举例:
INSERT INTO Person VALUES(1,'xiazdong');
INSERT INTO Person(name,id) VALUES('xiazdong',1);
INSERT INTO Person
SELECT DISTINCT id FROM Person;
UPDATE Person SET age=20,name='xiazdong' WHERE id=1; //将id=1的人姓名改成xiazdong,年龄改成20;
SQL事务