【数据库复习】SQL

 

SQL:Structured Query Language(结构化查询语言);数据库

 

数据模型:对于数据的描述方式;好比关系数据模型是用二维表来描述,层次数据模型用树来描述数据。

数据模型由三部分组成:

(1)数据结构:定义数据的结构;

(2)数据操做:CRUD;

(3)数据约束:好比键约束、完整性约束等;

 

数据模型介绍

 

1.关系数据模型

 

将数据描述成二维表的形式,例如:

关系模型的特色:

(1)建模方便,操做简单(SQL);

(2)高效性(访问快速)、易用性;

(3)描述数据单一,即用表来表述数据;
 

2.半结构化数据模型

 

将数据描述成相似于XML的形式,例如:


 

3.对象关系模型

 

关系的属性不只仅是基本数据类型,而且每一个关系都有相关的方法;


 

4.层次模型

 

基于树结构的模型,在物理层次进行操做,很不方便;

 

5.网状模型

 

基于图结构的模型,也是在物理层次进行操做,很不方便;

 

关系模型术语

 

关系模型约定:属性具备原子性,即每一个属性都是基本的数据类型;

关系:二维表;

属性:每列为一个属性;

元组:每一行为一个元组,即记录;

份量(component):元组的每一个属性值就是一个份量;

表模式:由表名、表的属性、属性的数据类型组成;

数据库模式:多个表的模式;

:属性的数据类型;

实例:表就是关系的实例,固然,若是随着时间的改变,表发生改变,可是他仍然是关系的实例;

当前实例 :当前表的数据集;

超键:可以肯定一个元组的属性集;

候选键:最小的超键;

主键:设计者选定的候选键;

主属性:包含于候选码的一个属性;好比若是候选码为AB,则主属性能够是A,B,只要包含于候选码的单个属性便可;
数据结构

通常咱们都是经过新建一个虚拟键做为主键,好比学校里有学号,社会上有身份证号,书有书号等;

就上图来讲,

关系:account;

属性:account_number、balance;

元组:(A-101,500),....;

第一个元组的第一个份量:A-101;

表模式:account(account_number,balance);

数据库模式未知;

account_number的域:string,balance的域为int;

实例为如今account的这张表;

超键能够为(account_number,balance)、(account_number);

候选键为(account_number);

主键根据设计者自行选定;


问:比较如下两个关系,是否为同一个关系?




答:是的,这两个关系只是把属性的顺序以及元组的顺序改变了,可是他们仍是同一个关系,只是表现形式不一样;


SQL初步


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

字符串是用单引号括起来的;

 

DDL语句

 

(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)和VARCHAR(3)有什么区别?


答:以下图所示:  虽然这两种数据类型的存储方式不一样,可是若是char(3)类型的'a'和varchar(3)类型的'a'是相等的;



注意:SQL中string是用单引号括起来的;


问:数据库和表的关系?


答:数据库中含有多个表,不能单纯的建立表;


问:PRIMARY KEY和UNIQUE有什么区别?


答:PRIMARY KEY 和UNIQUE都表示属性可以区别全部元组,可是PRIMARY KEY 不能存在NULL值,而UNIQUE容许NULL值;


问:相似PRIMARY KEY这种约束声明在哪?


答:能够声明在两个地方,

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)

);

 

 

示例:

 

 

SQL查询


原始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;

举例:

loan left outer join borrower on loan.loan_number = borrower.loan_number

loan  natural right outer join  borrower



子查询


子查询须要从里向外分析


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 ageavg(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事务


START TRANSACTION:开始事务;
COMMIT:提交事务;
ROLLBACK:回滚事务;
咱们是在 START TRANSACTION 语句和COMMIT语句之间放置SQL的DDL和DML语句;在事务A没有提交以前,其余查询者是查询不到事务A对于数据库的更改;

举例:
START TRANSACTION
INSERT INTO Person VALUES ( 1,'xiazdong-1' );
INSERT INTO Person VALUES ( 2,'xiazdong-2' );
COMMIT
上面的事务操做中,若是此事务提交以前,其余的查询者是看不到(1,'xiazdong-1')(2,'xiazdong-2')插入数据库的;


只读事务与读写事务


若是在开始事务以前告诉数据库此事务是只读事务,则能够并行执行;
SET TRANSACTION READ ONLY; //只读,能并行执行;
SET TRANSACTION READ WRITE; //读写,不能并行执行;

脏数据与读脏数据


脏数据:尚未提交的事务所写的数据;
读脏数据:读取那些尚未提交的事务修改的数据;
脏读是很差的,由于若是读取了事务A的写的数据,而事务A最后rollback了,则后果很严重;


事务的隔离层次

分为四种:

SET TRANSACTION READ WRITE  ISOLATION LEVEL  READ UNCOMMITED;  //容许脏读
SET TRANSACTION READ ONLY  ISOLATION LEVEL  READ COMMITED;    //不容许脏读
SET TRANSACTION ISOLATION LEVEL  SERIALIZABLE; // 默认选项,串行执行事务
SET TRANSACTION ISOLATION LEVEL  REPEATABLE READ;  // 若是执行查询语句A,获得结果,对此结果进行快照,若是下次在提交事务以前执行查询语句A,则仍是获得这个快照的结果;

可重复读举例:

事务A执行:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM PERSON;
此时得到告终果以下:
此时SELECT * FROM PERSON 得到快照结果如上图;
事务B执行:
UPDATE Person SET name ='xiazdong' where name='xzdong';
执行完事务B以后,按照常理来讲person表变化了,可是在事务A中执行SELECT * FROM PERSON时仍然获得的是以下图:


注:固然若是在事务A中执行好比
SELECT  name from person
时获得的是最新的结果:


可重复读的特色就是会对第一次执行的查询语句设置快照,使得之后执行此语句时无论数据库变成什么样了,执行此语句的结果仍是那个快照;





存储过程

存储过程遵循SQL2003标准;
存储过程是存储在数据库中的一套SQL语句;

(1)和函数的区别:
            --函数有返回值,存储过程没有返回值;
                     注意:函数到达返回值不会结束函数,而是继续执行,有可能会改变返回值;
            --函数的参数都是IN模式,而存储过程的参数模式有IN、OUT、INOUT,分别表示输入、输出、输入输出;
----------------------------------------------------------------------
    CREATE PROCEDURE [name] ([模式、参数、类型])
        [DECLARE声明局部变量]
        [BEGIN]
            [语句]
        [END]
-----------------------------------------------------------------------
    CREATE FUNCTION [name] ([参数、类型]) RETURNS [类型]
        .....
        RETURN [值];
-----------------------------------------------------------------------
注意:函数的返回语句不会真的结束函数执行,而会一直执行下去,所以返回值可能还会改变;好比:

CREATE FUNCTION f3() RETURNS int
return 1;
SELECT * FROM Person;

这个函数执行到RETURN 1 时会继续执行,而且列出Person表的数据;




最简单的存储过程实例:

CREATE PROCEDURE pro ()   //一次执行3个插入语句;
    INSERT INTO Person VALUES(1,'xiazdong-1');
    INSERT INTO Person VALUES(2,'xiazdong-2');
    INSERT INTO Person VALUES(3,'xiazdong-3');

声明局部变量

DECLARE 变量名   类型;声明必须在执行语句以前定义;

好比:DECLARE age int;

赋值语句

SET [变量名] = [值];

SET age = age+1;

IF语句

IF [Condition] THEN 
        [statement]
ELSEIF [Condition] THEN 
        [statement]
ELSE 
    [statement]
END IF;

好比:

CREATE PROCEDURE p1(OUT put int)
DECLARE s int;
SET s = 0;
IF id=1 THEN 
      s=1;
ELSEIF id=2 THEN 
       s=2;
ELSE 
        s=0;
END IF;
SET put = s;

FOR语句

FOR [loopname] AS [cursor name] CURSOR FOR [语句]
DO
    [statement]
END FOR;

好比:

CREATE PROCEDURE sumID1(OUT s int)
BEGIN

DECLARE len int;
DECLARE ss int;
DECLARE done int DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
SET ss = 0;
FOR name AS cur1 CURSOR FOR SELECT id FROM person;

DO
SET ss = ss  + id;
END FOR;
SET s=ss;
END


LOOP语句

[loopname] :LOOP
    [statement]
END LOOP;

好比:
aa: LOOP
        SET ss = ss+1;
IF ss>10 THEN LEAVE aa;  END IF;
END LOOP;


调用存储过程

CALL [存储过程名] ([参数]);


调用函数

[函数名]([参数]);
好比:
fun();

游标使用

DECLARE [cursor name] CURSOR FOR [query];
DECLARE [ CONTINUE|EXIT| UNDO  ] HANDLER FOR SQLSTATE '02000' [语句];    //异常处理
CONTINUE表名 执行完异常处理(即语句)以后继续执行抛出异常的后一句话;

好比:

DECLARE done int DEFAULT 0;
DECLARE  cur1  CURSOR  FOR  SELECT id FROM person;
DECLARE  CONTINUE  HANDLER FOR  SQLSTATE '02000'  SET  done = 1;


MySQL的存储过程

MySQL不支持FOR语句;

基本存储过程实例

CREATE PROCEDURE insertTuple (IN id int,IN name varchar(30), IN age int)
BEGIN
DECLARE tmp int;

INSERT INTO Person values(id,name,age);
SELECT * FROM Person;
END;

CALL insertTuple(4,'xiazdong',20);  //调用insertTuple存储过程;


IF语句的应用

CREATE PROCEDURE proc2 (IN id1 int)
BEGIN
IF id1=1 THEN 
SELECT * FROM Person WHERE id=1;
ELSEIF id1=2 THEN
SELECT * FROM Person WHERE id=2;
ELSE
SELECT * FROM Person WHERE id<>1 AND id<>2;
END IF;
END


CALL proc2 (2)



LOOP语句的应用

CREATE PROCEDURE sumID(OUT s int)
BEGIN
DECLARE ss int;
SET ss = 0;
aa: LOOP
SET ss = ss+1;
IF ss>10 THEN LEAVE aa; 
                         END IF;
END LOOP  aa;   //MySQL须要加上循环名;
SET s=ss;
END


游标应用


CREATE PROCEDURE sumID1(OUT s int)
BEGIN

DECLARE len int;
DECLARE ss int;
DECLARE done int DEFAULT 0;
DECLARE cur1 CURSOR  FOR SELECT id FROM person;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN cur1; 
SET ss = 0;
aa: LOOP
FETCH FROM cur1 INTO len;
IF done=1 THEN 
LEAVE aa;
ELSE
SET ss = ss+ len;
END IF;
END LOOP aa;
CLOSE cur1;
SET s=ss;
END