数据库基础

数据库基础

 

知识预览

     数据库的简介

     MySQL--关系型数据库管理系统

         

第一章数据库的简介

 

数据库

    数据库(DataBase,DB)是指长期存储在计算机内的,有组织,可共享的数据的集合。

        数据库中的数据按一定的数学模型组织、描述和存储,具有较小的冗余,较高的数据独立性和易扩展性,并可为各种用户共享。

       

数据库管理系统软件

    数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,简称DBMS。

        它对数据库进行统一的管理和控制,以保证数据库的安全性和完整性。

        用户通过DBMS访问数据库中的数据,数据库管理员也通过DBMS进行数据库的维护工作。

        它可使多个应用程序和用户用不同的方法在同时或不同时刻去建立,修改和询问数据库。

       

        大部分DBMS提供数据定义语言DDL(Data Definition Language)和数据操作语言DML(Data Manipulation Language),供用户定义数据库的模式结构与权限约束,实现对数据的追加、删除等操作。

    数据库管理系统是数据库系统的核心,是管理数据库的软件。

        数据库管理系统就是实现把用户意义下抽象的逻辑数据处理,转换成为计算机中具体的物理数据处理的软件。

        有了数据库管理系统,用户就可以在抽象意义下处理数据,而不必顾及这些数据在计算机中的布局和物理位置。

    常见的数据库管理软件:甲骨文的oracle,IBM的db2,sql server,Access,MySQL(开源,免费,跨平台)。

       

数据库系统

    数据库系统DBS(Data Base System,简称DBS)通常由软件、数据库和数据管理员组成。

            软件主要包括操作系统、各种宿主语言、实用程序以及数据库管理系统。

            数据库由数据库管理系统统一管理,数据的插入、修改和检索均要通过数据库管理系统进行。

            数据管理员负责创建、监控和维护整个数据库,使数据能被任何有权使用的人有效使用。

 

MySQL

MySQL的管理

--安装

        --linux下:

yum -y install mariadb mariadb-server

OR

yum -y install mysql mysql-server

        --windows下:

http://dev.mysql.com/downloads/mysql/

        --Linux下启动

service mysqld start  --开启

chkconfig mysqld on   --设置开机自启

OR

systemctl start mariadb          --开启

systemctl enable mariadb       --设置开机自启

 

--查看

ps aux |grep mysqld   --查看进程

netstat -an |grep 3306 --查看端口

 

--设置密码

mysqladmin -u root password '123'   --设置初始密码,初始密码为空因此-p选项没有用

mysqladmin -u root -p123 password '1234' --修改root用户密码

 

--登录

mysql               --本地登录,默认用户root,空密码,用户为[email protected]

mysql -u root -p 1234 --本地登录,指定用户名和密码,用户为[email protected]

mysql -u root -p 1234 -h 192.168.31.95 --远程登录,用户为[email protected]

 

--MySQL的常用命令

 

--启动mysql服务与停止mysql服务命令:

   net start mysql

   net stop  mysql

 

--登陆与退出命令:

   mysql -h 服务器IP -P 端口号 -u  用户名 -p 密码

        --mysql -h 127.0.0.1 -P 3306 -u root -p 123

       

--配置文件

/* my.ini文件:[mysql] default-character-set=gbk

               [mysqld] character-set-server=gbk */

                           

?         (\?) 显示帮助信息

clear     (\c) 明确当前输入语句

connect   (\r) 连接到服务器,可选参数为数据库和主机

delimiter (\d) 设置语句分隔符

ego       (\G) 发送命令到MySQL服务器,并显示结果

exit      (\q) 退出MySQL等同于quit

go        (\g) 发送命令到MySQL服务器

help      (\h) 显示帮助信息

notee     (\t) 不写输出文件

print     (\p) 打印当前命令

prompt    (\R) 改变MySQL提示信息

quit      (\q) 退出MySQL

rehash    (\#) 重新完成散列

source    (\.) 执行一个SQL脚本文件,以一个文件名作为参数。

status    (\s) 以服务器获取MySQL的状态

tee       (\T) 设置输出文件,并将信息添加到所有给定的输出文件

use       (\u) 用另一个数据库,数据库名称作为参数

charset   (\C) 切换到另一个字符集

warnings  (\W) 每一个语句之后显示警告

nowarning (\w) 每一个语句之后不显示警告

 

SQL及其规范

SQL(Structured Query Language结构化查询语言)是一种数据库查询语言和程序设计语言,主要用于管理数据库中的数据,如存取数据、查询数据、更新数据等。

SQL是专为数据库而建立的操作命令集,是一种功能齐全的数据库语言。

        在使用它时,只需要发出"做什么"的命令,"怎么做"是不用使用者考虑的。

        SQL功能强大、简单易学、使用方便,已经成为了数据库操作的基础,并且现在几乎所有的数据库均支持SQL。

<1> 在数据库系统中,SQL语句不区分大小写。但字符串常量区分大小写。建议命令大写,表名库名小写;

<2> SQL语句可单行或多行书写,以";"结尾。关键词不能跨多行或简写。

<3> 用空格和缩进来提高语句的可读性。子句通常位于独立行,便于编辑,提高可读性。

        SELECT * FROM tb_table

             WHERE NAME="YUAN";

<4> 注释:单行注释:--

          多行注释:/*......*/

<5>SQL语句可以折行操作

<6>SQL语言由DDL,DML,DQL和DCL组成

   (1)数据库定义语言(Data Definition Language,DDL)

      数据库定义语言主要用于定义数据库、表等,其中包括CREATE语句、ALTER语句和DROP语句。

                        CREATE语句用于创建数据库、数据表等,ALTER语句用于修改表的定义等,DROP语句用于删除数据库、删除表等。

   (2)数据库操作语言(Data Manipulation Language,DML)

      数据库操作语言主要用于数据库、表进行添加、修改、删除操作,其中包括INSERT语句、UPDATE语言和DELETE语句。

                        INSERT语句用于插入数据,UPDATE语句用于修改数据,DELETE语句用于删除数据。

   (3)数据库查询语言(Data Query Language,DQL)

      数据库查询语言主要用于查询语言,也就是指SELECT语句。

                        SELECT语句查询数据库中的一条或多条数据。

   (4)数据库控制语言(Data Control Language,DCL)

      数据库控制语言主要用于控制用户的访问权限,其中包括GRANT语句、REVOKE语句、COMMIT语句和ROLLBACK语句。

                        GRANT语句用于给用户增加权限,REVOKE语句用于收回用户的权限,COMMIT语句用于提交事务,ROLLBACK语句用于回滚事务。

 

第二章 数据库和表基本操作                                       

 

数据库操作

-- 1.创建数据库(在磁盘上创建一个对应的文件夹)

    CREATE DATABASE [IF NOT EXISTS] 库名 [CHARACTER SET xxx]   --xxx表示编码取值为utf8或者gbk

                                                               --[IF NOT EXISTS]此可选项的意思是如果不存在表就创建,如果存在表则不创建。

                                                                                                                                

-- 2.查看数据库

    SHOW DATABASES;--查看所有数据库

    SHOW CREATE DATABASE 库名; --查看数据库的创建方式

 

-- 3.修改数据库

    ALTER DATABASE 库名 [CHARACTER SET xxx];    --(一般不需要)

 

-- 4.删除数据库

    DROP DATABASE [IF EXISTS] 库名;

   

-- 5.使用数据库

    USE 库名; --切换数据库

                     --注意:进入到某个数据库后没办法再退回之前状态,但可以通过USE进行切换

    SELECT DATABASE();--查看当前使用的数据库

 

MySQL数据类型

MySQL支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型。

 

数值类型

下面的表显示了需要的每个整数类型的存储和范围。

 

--整数类型

数值类型         字节数   无符号数取值类型            有符号数取值类型

TINYINT          1        (0,255)                      (-128,127)

SMALLINT                2        (0,65535)                    (-32768,32767)

MEDIUMINT        3        (0,16777215)                 (-8388608,8388607)

INT或INTEGER     4        (0,4294967295)               (-2147483648,2147483647)

BIGINT           8        (0,18446744073709551615)     (-9223372036854775808,9223372036854775807)

--浮点型类型和定点数类型

数值类型         字节数   无符号数取值类型            有符号数取值类型

FLOAT            4

DOUBLE           8

DECIMAL(M,D)     M+2

   --注意DECIMAL类型的取值范围与DOUBLE类型相同。

   --注意的是DECIMAL类型的有效取值范围是由M和D决定的。

   --其中,M表示的是数据的长度,D表示的是小数点后的长度。

  

--日期和时间类型

表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。

每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。

 

类型           字节数(大小)       范围                                 格式                     用途   

DATE           3                  1000-01-01/9999-12-31                YYYY-MM-DD               日期值

TIME           3                  -838:59:59/838:59:59                 HH:MM:SS                 时间值或持续时间

YEAR           1                  1901/2155                            YYYY                     年份值

DATETIME       8                  1000-01-01 00:00:00/                 YYYY-MM-DD               混合日期和时间值

                                                                     9999-12-31 23:59:59                  HH:MM:SS              

TIMESTAMP      4                  1970-01-01 00:00:01/                 YYYY-MM-DDH              混合日期和时间值

                                                                     2038-01-19 03:14:07                  HH:MM:SS                 时间数

 

--字符串类型

字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。

该节描述了这些类型如何工作以及如何在查询中使用这些类型。

类型           字节数(大小)       用途

CHAR           0-255字节          定长字节符

VARCHAR        0-65535字节        变长字节符

BLOB           0-65535字节        二进制形式的长文本数据

TINYBLOB       0-255字节          不超过255个字符的二进制字符串

MEDIUMBLOB     0-16777215字节     二进制形式的中等长度文本数据

LONGBLOB       0-4294967295字节   二进制形式的极大文本数据

TEXT           0-65535字节        长文本数据

TINYTEXT       0-255字节          短文本字符串

MEDIUMTEXT     0-16777215字节     中等长度文本数据

LONGTEXT       0-4294967295字节   极大文本数据

 

/* CHAR和VARCHAR类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。

   BINARY和VARBINARY类类似于CHAR和VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。

   BLOB是一个二进制大对象,可以容纳可变数量的数据。有4种BLOB类型:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。它们只是可容纳值的最大长度不同。

   有4种TEXT类型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。这些对应4种BLOB类型,有相同的最大长度和存储需求。

 */

 

数据表操作

--1.创建表(类似于一个excel表)

--基本语法

CREATE TABLE 表名(

            field1 type[完整性约束条件],

            field2 type,

            ...

            fieldn type

        )[CHARACTER SET XXX];

 

--创建一个员工表employee

mysql>CREATE TABLE employee(

            id INT PRIMARY KEY AUTO_INCREMENT,

            name VARCHAR(20),

            gender BIT DEFAULT 1,                -- gender CHAR(1)  DEFAULT 1   --或者 TINYINT(1)

            birthday DATE,

            entry_date DATE,

            job VARCHAR(20),

            salary DOUBLE(4,2) unsigned,

            resume TEXT                          -- 注意,这里作为最后一个字段不加逗号

                 );

                  

    /* 约束:

       PRIMARY KEY (非空且唯一):能够唯一区分出当前记录的字段称为主键!

       UNIQUE 唯一

       NOT NULL 非空

       AUTO_INCREMENT 主键字段必须是数字类型。使用AUTO_INCREMENT设置字段值自动增加。

       外键约束 FOREIGN KEY  */

 

--2.查看表信息

    DESC 表名; --查看表结构,即查看表的字段信息,其中包括字段名、字段类型等信息

       

    SHOW COLUMNS FROM 表名;  --查看表结构

       

    SHOW TABLES; --查看当前数据库中的所有的表

       

    SHOW CREATE TABLE 表名; --查看当前数据库表建表语句

 

--3.修改表结构

   --(1)增加列(字段)      --默认在表已有字段的后面添加

      ALTER TABLE 表名 ADD [COLUMN] 列名 类型[完整性约束条件][FIRST|AFTER 字段名];

                 --ALTER TABLE user ADD addr VARCHAR(20) NOT NULL UNIQUE FIRST/AFTER username;

                                                                  --FIRST用于将新添加的字段设置为表的第一个字段

                                                                                                                            --AFTER用于将新添加的字段添加到指定的"已存在字段名"的后面

                

                 --添加多个字段

                         ALTER TABLE employee

                                  ADD addr VARCHAR(20),

                                  ADD age  INT FIRST,

                                  ADD depart VARCHAR(20) AFTER name;

 

   --(2)修改一列类型

      ALTER TABLE 表名 MODIFY 列名 类型 [完整性约束条件][FIRST|AFTER 字段名];

                 --ALTER TABLE employee MODIFY age TINYINT DEFAULT 20;

                 --ALTER TABLE employee MODIFY age TINYINT AFTER id;

  

   --(3)修改列名

      ALTER TABLE 表名 CHANGE [COLUMN] 列名 新列名 类型 [完整性约束条件][FIRST|AFTER 字段名];

                 --ALTER TABLE employee CHANGE age Age INT DEFAULT 28 FIRST;

 

   --(4)删除一列

      ALTER TABLE 表名 DROP [COLUMN] 列名;

      --思考:删除多列呢?

          ALTER TABLE 表名 DROP [COLUMN] 列名1,

                                             DROP [COLUMN] 列名2;

          --删一个填一个呢?

      ALTER TABLE employee

            ADD salary FLOAT(6,2) UNSIGNED NOT NULL AFTER name,

            DROP addr;   

 

   --(5)修改表名

      ALTER TABLE 旧表名 RENAME [TO] 新表名;

         

   --(6)修改表所用的字符集   

      ALTER TABLE student CHARACTER SET utf8;--字符集为utf8

      ALTER TABLE student CHARACTER SET gbk; --字符集为gbk

         

--4.删除表

          DROP TABLE 表名;

       

表的约束

      PRIMARY KEY      --主键约束,用于唯一标识对应的记录

          FOREIGN KEY      --外键约束

          NOT NULL        --非空约束

          UNIQUE         --唯一性约束

          DEFAULT          --默认值约束,用于设置字段的默认值

         

主键约束  --唯一标识表中的记录

    --语法:

               字段名 数据类型 PRIMARY KEY

  单字段主键

mysql>CREATE TABLE users(

            id INT PRIMARY KEY,

            name VARCHAR(20),

            city VARCHAR(20)

        );

    主键字段特点:非空且唯一

 

  多字段联合主键

mysql>CREATE TABLE users2(

            id INT,

            name VARCHAR(20),

            city VARCHAR(20),

            PRIMARY KEY(name,id)

          );

    <1> 一张表只能有一个主键

    <2> 主键类型不一定非是整型

       

        --添加主键,

          ALTER TABLE 表名 ADD PRIMARY KEY(字段名称,...);

    --删除主键

          ALTER TABLE users DROP PRIMARY KEY;

        --每张表必须有主键

mysql> CREATE TABLE test5(num INT AUTO_INCREMENT);

    ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key

        --修改如下

mysql>CREATE TABLE test(num INT PRIMARY KEY AUTO_INCREMENT);

       

        --思考,如何删除主键?

          ALTER TABLE test MODIFY id INT;   -- AUTO_INCREMENT没了,但这样写主键依然存在,所以还要加上下面这句

      ALTER TABLE test DROP PRIMARY KEY;-- 仅仅用这句也无法直接删除主键

非空约束  --字段的值不能为NULL

    字段名 数据类型 NOT NULL

mysql>CREATE TABLE users3(

            id INT PRIMARY KEY,

                         name VARCHAR(20) NOT NULL,

                         grade FLOAT

                 );

唯一约束  --用于保证数据表中字段的唯一性,即表中字段的值不能重复出现。

mysql>CREATE TABLE users4(

                         id INT PRIMARY KEY,

                         stu_id INT UNIQUE,

                         name VARCHAR(20) NOT NULL

                 );

默认约束  --用于给数据表中的字段制定默认值,即当在表中插入一条新纪录时,如果没有给这个字段赋值,那么,数据库系统会自动为这个字段插入默认值。

mysql>CREATE TABLE users5(

                         id INT PRIMARY KEY AUTO_INCREMENT,

                         stu_id INT UNIQUE,

                         grade FLOAT DEFAULT 0

                 );

 

索引

--一、索引简介

        --索引在MySQL中也叫做"键",是存储引擎用于快速找到记录的一种数据结构。

        --索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。

        --索引优化应该是对查询性能优化最有效的手段了。

        --索引能够轻易将查询性能提高好几个数量级。

        --索引相当于字典的音序表,如果要查某个字,如果不使用音序表,则需要从几百页中逐页去查。

        --索引特点:创建与维护索引会消耗很多时间与磁盘空间,但查询速度大大提高!

 

--二、索引语法

--1.创建表时创建索引:可以直接创建索引,这种方法最简单、方便

        --基本语法

        CREATE TABLE 表名 (

                         字段名1 数据类型 [完整性约束条件…],

                         字段名2 数据类型 [完整性约束条件…],

                         [UNIQUE | FULLTEXT | SPATIAL ] INDEX | KEY

                         [索引名] (字段名[(长度)] [ASC |DESC])

                 );       

        --注释:

                 (1)UNIQUE:可选参数,表示唯一索引;

                 (2)FULLTEXT:可选参数,表示全文索引;

                 (3)SPATIAL:可选参数,表示空间检索;

                 (4)INDEX 和 KEY:用来表示字段的索引,二者选一;

                 (5)索引名:可选参数,表示创建的索引的名称;

                 (6)字段名:指定索引对应字段的名称;

                 (7)长度:用于表示索引的长度;

                 (8)ASC 和 DESC:可选参数,ASC表示升序,DESC表示降序。

 

--①创建普通索引

   --是由INDEX或KEY定义的索引,它是MySQL中的基本索引类型,可以创建在任何数据类型上,其值是否唯一和非空由字段本身的约束条件所决定。

--示例:

mysql>CREATE TABLE employee1(

             id INT PRIMARY KEY AUTO_INCREMENT,

                          name VARCHAR(20),

                          resume VARCHAR(20),

                          INDEX index_emp_name(name)               --INDEX可以替换成KEY

        );

                

--②唯一性索引

   --是由UNIQUE定义的索引,该索引所在字段的值必须是唯一的。

--示例:

CREATE TABLE employee2(

                         id INT PRIMARY KEY AUTO_INCREMENT,

                         name VARCHAR(20),

                         bank_num CHAR(18) UNIQUE,

                         resume VARCHAR(30),

                         UNIQUE INDEX index_emp_name(name)

        );

                

--③全文索引

   --是由FULLTEXT定义的索引,它只能创建CHAR、VARCHAR或TEXT类型的字段上,而且只有MyISAM存储引擎支持全文索引。InnoDB存储引擎还不支持全文索引。

   --示例:

CREATE TABLE employee3(

                         id INT PRIMARY KEY AUTO_INCREMENT,

                         name VARCHAR(20),

                         resume VARCHAR(30),

                         FULLTEXT INDEX index_resume(resume)

                 )ENGINE=MyISAM;

                

--④单列索引

   指的是在表中单个字段上创建索引,它可以是普通索引,唯一性索引或者全文索引,只要保证该索引只对应表中一个字段即可。

  

--⑤多列索引

   指的是在表中多个字段上创建索引,只有在查询条件中使用了这些字段中的第一个字段时该索引才会被使用。

   例如,在employ4表的id、name和resume字段上创建一个多列索引,那么只有查询条件中使用了id字段时,该索引才会被使用。

        --示例:

        CREATE TABLE employee4(

                         id INT PRIMARY KEY AUTO_INCREMENT,

                         name VARCHAR(20),

                         resume VARCHAR(30),

                         INDEX index_emp(id,name,resume)

            );

 

--2.使用CREATE INDEX语句在已经存在的表上创建索引

CREATE [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名

        ON 表名(字段名[(长度)] [ASC |DESC]);

示例:CREATE INDEX index_emp_name on emp1(name);

 

--3.使用ALTER TABLE语句在已经存在的表上创建索引

ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL ] INDEX

        索引名 (字段名[(长度)]  [ASC |DESC]) ;

示例:ALTER TABLE emp2 ADD UNIQUE INDEX index_bank_num(band_num);

 

--三、删除索引

--1.使用ALTER TABLE删除索引

--语法:

    ALTER TABLE 表名 DROP {INDEX|KEY} 索引名;

--示例:

    ALTER TABLE employ1 DROP {INDEX|KEY} index_emp_name;

 

--2.使用DROP INDEX 删除索引

--语法:

        DROP INDEX 索引名 ON 表名;

--示例:

    DROP INDEX index_emp_name ON employ1;

    DROP INDEX bank_num ON employ2;

       

--四、索引测试实验

 

--创建表

mysql>CREATE TABLE Indexdb.t1(id INT,name VARCHAR(20));

 

--存储过程

mysql>DELIMITER $$      --将语句的结束符号从分号;临时改为两个$$(可以是自定义)

mysql>CREATE PROCEDURE autoinsert()

        BEGIN

            DECLARE i INT DEFAULT 1;

                 WHILE(i<500000) DO

                                          INSERT INTO Indexdb.t1 VALUES (i,'yuan');

                                          SET i=i+1;

                 END WHILE;

      END$$            

mysql>DELIMITER ;       --将语句的结束符号恢复为分号

 

--调用函数

mysql>CALL autoinsert();

 

-- 花费时间比较:

-- 创建索引前

   SELECT * FROM Indexdb.t1 WHERE id=300000;--0.32s

-- 添加索引

   CREATE INDEX index_id ON Indexdb.t1(id);

-- 创建索引后

   SELECT * FROM Indexdb.t1 WHERE id=300000;--0.00s

  

第三章

表记录操作

表记录之增,删,改

 

添加数据(增)

--1.INSERT语句插入数据

--语法:

     INSERT[INTO]表名(field1,filed2,.......) VALUES (value1,value2,.......);

         --注释:

                 --①插入的数据应与字段的数据类型相同;

                 --②数据的大小应在列的规定范围内,例如:不能将一个长度为80的字符串加入到长度为40的列中。

        --③在values中列出的数据位置必须与被加入的列的排列位置相对应。

        --④字符和日期型数据应包含在单引号中'zhang' '2013-04-20'

        --⑤插入空值:不指定某列的值或INSERT INTO table VALUE(NULL),则该列取空值。

        --⑥如果要插入所有字段可以省写列列表,直接按表中字段顺序写值列表INSERT INTO tab_name values(value1,value2,......);

 

--创建表 

mysql>CREATE TABLE employee_new(

            id INT PRIMARY KEY AUTO_INCREMENT,

            name VARCHAR(20) NOT NULL UNIQUE,

            birthday VARCHAR(20),

            salary FLOAT(7,2)

        );     

--插入数据

  --插入一条数据

    --INSERT语句中指定所有字段名

                 INSERT INTO employee_new (id,name,birthday,salary) VALUES (1,'yuan','1990-09-09',9000);                

    --INSERT语句中不指定字段名

                 INSERT INTO employee_new VALUES (2,'alex','1989-08-08',3000);

    --INSERT语句为表的指定字段添加数据,没有添加的数据为NULL;

                 INSERT INTO employee_new (name,salary) VALUES ('xialv',1000);

  -- 插入多条数据

                 INSERT INTO employee_new VALUES (4,'alvin1','1993-04-20',3000),

                                                                                    (5,'alvin2','1995-05-12',5000);

 

--SET插入: INSERT[INTO]表名 SET 字段名=值 

                    INSERT INTO employee_new SET id=12,name="alvin3";

 

更新数据(改)    

-- 2.修改表记录 

--语法:

    UPDATE 表名 SET field1=value1,field2=value2,......[WHERE 语句];

 

 /* UPDATE语法可以用新值更新原有表行中的各列。

    SET子句指示要修改哪些字段和要给予哪些值。

    WHERE子句指定应更新哪些行,如没有WHERE子句,则更新所有的行。*/

--示例: 

        --将id=1的员工出生日期修改为1989-10-24

      UPDATE employee_new SET birthday="1989-10-24" WHERE id=1;

    --将yuan的薪水在原有基础上增加1000元。

      UPDATE employee_new SET salary=salary+1000 WHERE name='yuan';

       

删除数据(删)

-- 3.删除表纪录

--语法:

     DELETE FROM 表名 [WHERE ....]

 

 /* 如果不跟WHERE语句则删除整张表中的数据

    跟WHERE语句,DELETE只能用来删除指定一行记录

    DELETE语句只能删除表中的内容,不能删除表本身,想要删除表,用DROP

    TRUNCATE TABLE也可以删除表中的所有数据,此语句首先摧毁表,再新建表。此种方式删除的数据不能在事务中恢复。

*/

--示例:

    --删除表中名称为’alex’的记录。

      DELETE FROM employee_new WHERE name='alex';

    --删除表中所有记录。

          DELETE FROM employee_new;-- 注意AUTO_INCREMENT没有被重置,即再向表中添加数据时,自动增加字段的值为删除时该字段的最大值加1。

                                      --重置:ALTER TABLE employee AUTO_INCREMENT=1;

    --使用TRUNCATE删除表中记录。

      TRUNCATE TABLE employee_new;--注意AUTO_INCREMENT被重置,即再次向表中添加数据时,自动增加的默认初始值重新由1开始。

 

思考:

    <1>  存储时间用VARCHAR可不可以呢?(可以)它与DATE数据类型又有什么区别呢?

    <2>  表中数据三条,id分别为1,2,3,突然插入一个id=7,那么下次作为主键的字增长的id会从几开始增长呢?(从7开始)

       

第四章 单表查询

表纪录之查(单表查询)

 

--查询表达式

SELECT [DISTINCT] * | field1,filed2 ...   FROM 表名

                      [WHERE 条件]

                      [GROUP BY field]

                      [HAVING 筛选]

                      [ORDER BY field]

                      [LIMIT 限制条数]

 

--创建表

mysql>CREATE TABLE ExamResult(

                         id INT PRIMARY KEY AUTO_INCREMENT,

                         name VARCHAR (20),

                         JS DOUBLE,

                         Django DOUBLE,

                         OpenStack DOUBLE

                 );

                

--查看表结构

mysql>DESC ExamResult;

+-----------+-------------+------+-----+---------+----------------+

| Field     | Type        | Null | Key | Default | Extra          |

+-----------+-------------+------+-----+---------+----------------+

| id        | int(11)     | NO   | PRI | NULL    | auto_increment |

| name      | varchar(20) | YES  |     | NULL    |                |

| JS        | double      | YES  |     | NULL    |                |

| Django    | double      | YES  |     | NULL    |                |

| OpenStack | double      | YES  |     | NULL    |                |

+-----------+-------------+------+-----+---------+----------------+

5 rows in set

 

--插入值

mysql>INSERT INTO ExamResult VALUES (1,"yuan",98,98,98),

                                                                            (2,"xialv",35,98,67),

                                                                            (3,"alex",59,59,62),

                                                                            (4,"wusir",88,89,82),

                                                                            (5,"alvin",88,98,67),

                                                                            (6,"yuan",86,100,55);

 

--查看表内容                                                                    

mysql>SELECT * FROM ExamResult;

+----+-------+----+--------+-----------+

| id | name  | JS | Django | OpenStack |

+----+-------+----+--------+-----------+

|  1 | yuan  | 98 |     98 |        98 |

|  2 | xialv | 35 |     98 |        67 |

|  3 | alex  | 59 |     59 |        62 |

|  4 | wusir | 88 |     89 |        82 |

|  5 | alvin | 88 |     98 |        67 |

|  6 | yuan  | 86 |    100 |        55 |

+----+-------+----+--------+-----------+

6 rows in set

                                                            

--(1)SELECT [DISTINCT] * | field1,field2,....FROM 表名;

        --其中FROM指定从哪张表筛选,*表示查找所有列,也可以指定一个列表明确指定要查找的列,DISTINCT用来剔除重复行。

--练习

        --使用SELECT语句中使用星号("*")通配符代替所有字段

        --查询表中所有学生的信息。

mysql>SELECT * FROM ExamResult;

+----+-------+----+--------+-----------+

| id | name  | JS | Django | OpenStack |

+----+-------+----+--------+-----------+

|  1 | yuan  | 98 |     98 |        98 |

|  2 | xialv | 35 |     98 |        67 |

|  3 | alex  | 59 |     59 |        62 |

|  4 | wusir | 88 |     89 |        82 |

|  5 | alvin | 88 |     98 |        67 |

|  6 | yuan  | 86 |    100 |        55 |

+----+-------+----+--------+-----------+

6 rows in set

 

        --使用SELECT语句查询指定字段

        --查询表中所有学生的姓名和对应的英语成绩。

mysql>SELECT name,JS FROM ExamResult;

+-------+----+

| name  | JS |

+-------+----+

| yuan  | 98 |

| xialv | 35 |

| alex  | 59 |

| wusir | 88 |

| alvin | 88 |

| yuan  | 86 |

+-------+----+

6 rows in set

 

        --DISTINCT关键字过滤表中重复数据。

        --SELECT DISTINCT field1,field2,... FROM表名

mysql>SELECT DISTINCT name,JS FROM ExamResult;

+-------+----+

| name  | JS |

+-------+----+

| yuan  | 98 |

| xialv | 35 |

| alex  | 59 |

| wusir | 88 |

| alvin | 88 |

| yuan  | 86 |

+-------+----+

6 rows in set

 

    --从查询结果可以看出,返回的记录中,name字段仍然出现了重复值.

        --这是因为DISTINCT关键字作用于name和JS两个字段,只有这两个字段的值都相同才被认为是重复数据。

 

--(2)SELECT也可以使用表达式,并且可以使用: 字段 AS 别名 或者 字段 别名

--练习

        --在所有学生分数上加10分特长分显示。

mysql>SELECT name,JS+10,Django+10,OpenStack+10 FROM ExamResult;

+-------+-------+-----------+--------------+

| name  | JS+10 | Django+10 | OpenStack+10 |

+-------+-------+-----------+--------------+

| yuan  |   108 |       108 |          108 |

| xialv |    45 |       108 |           77 |

| alex  |    69 |        69 |           72 |

| wusir |    98 |        99 |           92 |

| alvin |    98 |       108 |           77 |

| yuan  |    96 |       110 |           65 |

+-------+-------+-----------+--------------+

6 rows in set

 

     -- 统计每个学生的总分。

mysql> SELECt name,JS+Django+OpenStack FROM ExamResult;

+-------+---------------------+

| name  | JS+Django+OpenStack |

+-------+---------------------+

| yuan  |                 294 |

| xialv |                 200 |

| alex  |                 180 |

| wusir |                 259 |

| alvin |                 253 |

| yuan  |                 241 |

+-------+---------------------+

6 rows in set

 

     --使用别名表示学生总分。

mysql> SELECT name AS 姓名,JS+Django+OpenStack AS 总成绩 FROM ExamResult;

+-------+--------+

| 姓名  | 总成绩 |

+-------+--------+

| yuan  |    294 |

| xialv |    200 |

| alex  |    180 |

| wusir |    259 |

| alvin |    253 |

| yuan  |    241 |

+-------+--------+

6 rows in set  

        

mysql> SELECT name 姓名,JS+Django+OpenStack 总成绩 FROM ExamResult;

+-------+--------+

| 姓名  | 总成绩 |

+-------+--------+

| yuan  |    294 |

| xialv |    200 |

| alex  |    180 |

| wusir |    259 |

| alvin |    253 |

| yuan  |    241 |

+-------+--------+

6 rows in set

 

mysql> SELECT name JS FROM ExamResult;

+-------+

| JS    |

+-------+

| yuan  |

| xialv |

| alex  |

| wusir |

| alvin |

| yuan  |

+-------+

6 rows in set

       -- what will happen? (不是想要的查询结果)

           -->记得字段与字段之间加逗号

mysql> SELECT name,JS from ExamResult;

+-------+----+

| name  | JS |

+-------+----+

| yuan  | 98 |

| xialv | 35 |

| alex  | 59 |

| wusir | 88 |

| alvin | 88 |

| yuan  | 86 |

+-------+----+

6 rows in set

 

--(3)使用WHERE子句,进行过滤查询。

    --SELECT * | field1,field2,... FROM 表名 WHERE 条件表达式

--练习

    --查询姓名为XXX的学生成绩

mysql> SELECT * FROM ExamResult WHERE name='yuan';

+----+------+----+--------+-----------+

| id | name | JS | Django | OpenStack |

+----+------+----+--------+-----------+

|  1 | yuan | 98 |     98 |        98 |

|  6 | yuan | 86 |    100 |        55 |

+----+------+----+--------+-----------+

2 rows in set

 

    --查询姓名为XXX的学生JS成绩

mysql> SELECT id,name,JS FROM ExamResult WHERE name='yuan';

+----+------+----+

| id | name | JS |

+----+------+----+

|  1 | yuan | 98 |

|  6 | yuan | 86 |

+----+------+----+

2 rows in set   

    

    --where字句中可以使用:

        --关系运算符:

            > < >= <= <> !=

        --带BETWEEN AND 关键字的查询  

                         BETWEEN 80 AND 100 值在80到100之间

        --带IN关键字的查询

                  IN(80,90,100) 值是80或90或100

        --带LIKE关键字的查询  

                         LIKE '匹配字符串'

            /* 匹配字符串指定用来匹配的字符串,其值可以是一个普通字符串;

                            也可以是百分号(%)或者下划线(_)的统配字符串。

               如果是%则表示任意多字符,此例如唐僧,唐国强

               如果是_则表示一个字符唐_,只有唐僧符合。两个_则表示两个字符:__

                         */   

                 --逻辑运算符

            在多个条件直接可以使用逻辑运算符 AND OR NOT

                 --空值查询

--练习

        --查询JS成绩大于90分的同学

mysql> SELECT id,name,JS FROM ExamResult where JS>90;

+----+------+----+

| id | name | JS |

+----+------+----+

|  1 | yuan | 98 |

+----+------+----+

1 row in set    

      

    -- 查询总分大于200分的所有同学

mysql> SELECT name,JS+Django+OpenStack AS 总成绩 FROM ExamResult

                                                 WHERE JS+Django+OpenStack>200;

+-------+--------+

| name  | 总成绩 |

+-------+--------+

| yuan  |    294 |

| wusir |    259 |

| alvin |    253 |

| yuan  |    241 |

+-------+--------+

4 rows in set       

   

    -- 查询JS分数在 80-100之间的同学。

mysql> SELECT name,JS FROM ExamResult WHERE JS BETWEEN 80 AND 100;

+-------+----+

| name  | JS |

+-------+----+

| yuan  | 98 |

| wusir | 88 |

| alvin | 88 |

| yuan  | 86 |

+-------+----+

4 rows in set

 

    -- 查询Django分数为75,98,77的同学。

mysql> SELECT name,Django FROM ExamResult WHERE Django IN (75,98,77);

+-------+--------+

| name  | Django |

+-------+--------+

| yuan  |     98 |

| xialv |     98 |

| alvin |     98 |

+-------+--------+

3 rows in set

 

    --查询所有姓wu的学生成绩。

mysql> SELECT * FROM ExamResult WHERE name LIKE 'wu%';

+----+-------+----+--------+-----------+

| id | name  | JS | Django | OpenStack |

+----+-------+----+--------+-----------+

|  4 | wusir | 88 |     89 |        82 |

+----+-------+----+--------+-----------+

1 row in set           

 

    --查询JS分>90,Django分>90的同学。

mysql> SELECT id,name FROM ExamResult WHERE JS>90 AND Django >90;

+----+------+

| id | name |

+----+------+

|  1 | yuan |

+----+------+

1 row in set

    

        --因原表中并无缺考Djiango的学生信息,需要重新插入一条Djiango为NULL的信息。

mysql> INSERT INTO ExamResult(id,name) VALUES(9,'lv');

Query OK, 1 row affected

 

mysql> SELECT * FROM ExamResult;

+----+-------+------+--------+-----------+

| id | name  | JS   | Django | OpenStack |

+----+-------+------+--------+-----------+

|  1 | yuan  |   98 |     98 |        98 |

|  2 | xialv |   35 |     98 |        67 |

|  3 | alex  |   59 |     59 |        62 |

|  4 | wusir |   88 |     89 |        82 |

|  5 | alvin |   88 |     98 |        67 |

|  6 | yuan  |   86 |    100 |        55 |

|  9 | lv    | NULL | NULL   | NULL      |

+----+-------+------+--------+-----------+

7 rows in set

 

        --查找缺考Django的学生的姓名

 mysql> SELECT id,name FROM ExamResult WHERE Django IS NULL;

+----+------+

| id | name |

+----+------+

|  9 | lv   |

+----+------+

1 row in set                  

   

--(4)ORDER BY 指定排序的列,排序的列即可以是表中的列名,也可以是SELECT 语句后指定的别名。

        --SELECT * | field1,field2... FROM tab_name ORDER BY field [ASC|DESC]

              --ASC 升序、DESC 降序,其中ASC为默认值 ORDER BY 子句应位于SELECT语句的结尾。

--练习:

    --对JS成绩排序后输出(默认升序)

mysql> SELECT * FROM ExamResult ORDER BY JS;

+----+-------+------+--------+-----------+

| id | name  | JS   | Django | OpenStack |

+----+-------+------+--------+-----------+

|  9 | lv    | NULL | NULL   | NULL      |

|  2 | xialv |   35 |     98 |        67 |

|  3 | alex  |   59 |     59 |        62 |

|  6 | yuan  |   86 |    100 |        55 |

|  4 | wusir |   88 |     89 |        82 |

|  5 | alvin |   88 |     98 |        67 |

|  1 | yuan  |   98 |     98 |        98 |

+----+-------+------+--------+-----------+

7 rows in set

 

    --对总分排序按从高到低的顺序输出

mysql> SELECT name,(IFNULL(JS,0)+IFNULL(Django,0)+IFNULL(OpenStack,0)) 总成绩 FROM ExamResult

                                                                                                                                                                  ORDER BY 总成绩 DESC;

+-------+--------+

| name  | 总成绩 |

+-------+--------+

| yuan  |    294 |

| wusir |    259 |

| alvin |    253 |

| yuan  |    241 |

| xialv |    200 |

| alex  |    180 |

| lv    |      0 |

+-------+--------+

7 rows in set

 

    --对姓a的学生成绩排序输出

mysql> SELECT name,(IFNULL(JS,0)+IFNULL(Django,0)+IFNULL(OpenStack,0))总成绩 FROM ExamResult

                                                                                                                                                                 WHERE name LIKE 'a%'

                                                                                                                                                                 ORDER BY 总成绩 DESC;

+-------+--------+

| name  | 总成绩 |

+-------+--------+

| alvin |    253 |

| alex  |    180 |

+-------+--------+

2 rows in set

                                                                                                                                                                         

--(4)GROUP BY 分组查询

                                  --使用GROUP BY 按某个字段或者多个字段中的值进行分组,字段中值相同的为一组。

--创建表

mysql>CREATE TABLE order_menu(

             id INT PRIMARY KEY AUTO_INCREMENT,

             product_name VARCHAR(20),

             price FLOAT(6,2),

             born_date DATE,

             class VARCHAR (20)

        ); 

                

--查看表结构                                                                                                                                                --

mysql> DESC order_menu;

+--------------+-------------+------+-----+---------+----------------+

| Field        | Type        | Null | Key | Default | Extra          |

+--------------+-------------+------+-----+---------+----------------+

| id           | int(11)     | NO   | PRI | NULL    | auto_increment |

| product_name | varchar(20) | YES  |     | NULL    |                |

| price        | float(6,2)  | YES  |     | NULL    |                |

| born_date    | date        | YES  |     | NULL    |                |

| class        | varchar(20) | YES  |     | NULL    |                |

+--------------+-------------+------+-----+---------+----------------+          

5 rows in set

 

--插入值

mysql>INSERT INTO order_menu(product_name,price,born_date,class) VALUES  ("苹果",20,20170612,"水果"),

                                                                                                                                                        ("香蕉",80,20170602,"水果"),

                                                                                                                                                        ("水壶",120,20170612,"电器"),

                                                                                                                                                    ("被罩",70,20170612,"床上用品"),

                                                                         ("音响",420,20170612,"电器"),

                                                                         ("床单",55,20170612,"床上用品"),

                                                                         ("草莓",34,20170612,"水果");

 

--查询表内容

mysql> SELECT * FROM order_menu;

+----+--------------+-------+------------+----------+

| id | product_name | price | born_date  | class    |

+----+--------------+-------+------------+----------+

|  1 | 苹果         |    20 | 2017-06-12 | 水果     |

|  2 | 香蕉         |    80 | 2017-06-02 | 水果     |

|  3 | 水壶         |   120 | 2017-06-12 | 电器     |

|  4 | 被罩         |    70 | 2017-06-12 | 床上用品 |

|  5 | 音响         |   420 | 2017-06-12 | 电器     |

|  6 | 床单         |    55 | 2017-06-12 | 床上用品 |

|  7 | 草莓         |    34 | 2017-06-12 | 水果     |

+----+--------------+-------+------------+----------+

7 rows in set

                                                                                                                       

        --注意,按分组条件分组后每一组只会显示第一条记录

            --GROUP BY字句,其后可以接多个列名,也可以跟HAVING子句,对GROUP BY 的结果进行筛选。

--练习     

    --按位置字段筛选

mysql> SELECT * FROM order_menu GROUP BY 5;

+----+--------------+-------+------------+----------+

| id | product_name | price | born_date  | class    |

+----+--------------+-------+------------+----------+

|  4 | 被罩         |    70 | 2017-06-12 | 床上用品 |

|  3 | 水壶         |   120 | 2017-06-12 | 电器     |

|  1 | 苹果         |    20 | 2017-06-12 | 水果     |

+----+--------------+-------+------------+----------+

3 rows in set

 

     --对购物表按类名分组后显示每一组商品的价格总和

mysql> SELECT class,SUM(price) FROM order_menu GROUP BY class;

+----------+------------+

| class    | SUM(price) |

+----------+------------+

| 床上用品 |     125.00 |

| 电器     |     540.00 |

| 水果     |     134.00 |

+----------+------------+

3 rows in set

 

         --对购物表按类名分组后显示每一组商品价格总和超过150的商品

mysql>  SELECT CLASS,SUM(price)FROM order_menu GROUP BY class

                                               HAVING SUM(price)>150;

+-------+------------+

| CLASS | SUM(price) |

+-------+------------+

| 电器  |     540.00 |

+-------+------------+

1 row in set

 

        /*注意:

          HAVING 和 WHERE两者都可以对查询结果进行进一步的过滤,差别有:

          <1>WHERE语句只能用在分组之前的筛选,HAVING可以用在分组之后的筛选;

          <2>使用WHERE语句的地方都可以用HAVING进行替换

          <3>HAVING中可以用聚合函数,WHERE中就不行。

        */             

                

    --GROUP_CONCAT() 函数

                 --1.功能:将GROUP BY 产生的同一分组中的值连接起来,返回一个字符串结果。

                 --2.语法:GROUP_CONCAT([DISTINCT] 要连接的字段 [ORDER BY 排序字段 ASC|DESC] [SEPARATOR '分隔符']);

                 --3.说明:通过使用DISTINCT可以排除重复值;

                                    --如果希望对结果中的值进行排序,可以使用ORDER BY 子句;

                                    --SEPARATOR是一个字符值,缺省为逗号。

                                         

--练习

        --以class分组,把price字段的值在一行打印出来,逗号分隔(默认);

mysql> SELECT class,GROUP_CONCAT(price) FROM order_menu GROUP BY class;

+----------+---------------------+

| class    | GROUP_CONCAT(price) |

+----------+---------------------+

| 床上用品 | 70.00,55.00         |

| 电器     | 120.00,420.00       |

| 水果     | 20.00,80.00,34.00   |

+----------+---------------------+

3 rows in set

 

        --以class分组,把price字段的值在一行打印出来,分号分隔;

mysql> SELECT class,GROUP_CONCAT(price SEPARATOR ';') FROM order_menu GROUP BY class;

+----------+-----------------------------------+

| class    | GROUP_CONCAT(price SEPARATOR ';') |

+----------+-----------------------------------+

| 床上用品 | 70.00;55.00                       |

| 电器     | 120.00;420.00                     |

| 水果     | 20.00;80.00;34.00                 |

+----------+-----------------------------------+

3 rows in set

 

        --以class分组,把去除重复的price字段的值在一行打印出来,逗号分隔;

mysql> SELECT class,GROUP_CONCAT(DISTINCT price) FROM order_menu GROUP BY class;

+----------+------------------------------+

| class    | GROUP_CONCAT(DISTINCT price) |

+----------+------------------------------+

| 床上用品 | 70.00,55.00                  |

| 电器     | 120.00,420.00                |

| 水果     | 20.00,80.00,34.00            |

+----------+------------------------------+

3 rows in set

        --以class分组,把price字段的值在一行打印出来,逗号分隔,按照price倒序排列;

mysql> SELECT class,GROUP_CONCAT(price ORDER BY price DESC ) FROM order_menu GROUP BY class;

+----------+------------------------------------------+

| class    | GROUP_CONCAT(price ORDER BY price DESC ) |

+----------+------------------------------------------+

| 床上用品 | 70.00,55.00                              |

| 电器     | 420.00,120.00                            |

| 水果     | 80.00,34.00,20.00                        |

+----------+------------------------------------------+

3 rows in set

          

--(5)聚合函数:先不要管聚合函数要干嘛,先把要求的内容查出来再包上聚合函数即可。

                 -- (一般和分组查询配合使用)

        --<1> 统计表中所有记录

            --COUNT(列名):统计行的个数

--练习             

        --统计一个班级共有多少学生?先查出所有的学生,再用COUNT包上

mysql> SELECT COUNT(*) FROM ExamResult;

+----------+

| COUNT(*) |

+----------+

|        7 |

+----------+

1 row in set

 

    --统计JS成绩大于70的学生有多少个?

mysql> SELECT COUNT(JS) FROM ExamResult WHERE JS>70;

+-----------+

| COUNT(JS) |

+-----------+

|         4 |

+-----------+

1 row in set

 

    --统计总分大于280的人数有多少?

mysql> SELECT COUNT(name) FROM ExamResult

                          WHERE (IFNULl(JS,0)+IFNULL(Django,0)+IFNULL(OpenStack,0))>280;

+-------------+

| COUNT(name) |

+-------------+

|           1 |

+-------------+

1 row in set

                   

    -- 注意:COUNT(*)统计所有行;     COUNT(字段)不统计null值.

 

            --SUM(列名):统计满足条件的行的内容和

    --统计一个班级JS总成绩?先查出所有的JS成绩,再用sum包上      

mysql> SELECT SUM(JS) AS JS总成绩 FROM ExamResult;

+----------+

| JS总成绩 |

+----------+

|      454 |

+----------+

1 row in set

 

     --统计一个班级各科分别的总成绩

mysql> SELECT SUM(JS) AS JS总成绩,

              SUM(Django) AS Django总成绩,

              SUM(OpenStack) AS OpenStack总成绩 FROM ExamResult;

+----------+--------------+-----------------+

| JS总成绩 | Django总成绩 | OpenStack总成绩 |

+----------+--------------+-----------------+

|      454 |          542 |             431 |

+----------+--------------+-----------------+

1 row in set

 

     --统计一个班级各科的成绩总和

mysql> SELECT SUM(IFNULL(JS,0)+IFNULL(Django,0)+IFNULL(OpenStack,0))

                                          AS 总成绩 FROM ExamResult;

+--------+

| 总成绩 |

+--------+

|   1427 |

+--------+

1 row in set

 

     -- 统计一个班级JS成绩平均分

mysql> SELECT SUM(JS)/COUNT(*) FROM ExamResult;

+-------------------+

| SUM(JS)/COUNT(*)  |

+-------------------+

| 64.85714285714286 |

+-------------------+

1 row in set

            -- 注意:sum仅对数值起作用,否则会报错。

 

            -- AVG(列名):用于求出某个字段所有值的平均值。

    --求一个班级JS平均分?先查出所有的JS分,然后用avg包上。

mysql> SELECT AVG(IFNULL(JS,0)) FROM ExamResult;

+-------------------+

| AVG(IFNULL(JS,0)) |

+-------------------+

| 64.85714285714286 |

+-------------------+

1 row in set

 

    --求一个班级总分平均分

mysql> SELECT AVG((IFNULL(JS,0)+IFNULL(Django,0)+IFNULL(OpenStack,0)))

                                                     FROM ExamResult ;

+----------------------------------------------------------+

| AVG((IFNULL(JS,0)+IFNULL(Django,0)+IFNULL(OpenStack,0))) |

+----------------------------------------------------------+

|                                       203.85714285714286 |

+----------------------------------------------------------+

1 row in set

 

            --Max()、Min():最大值、最小值

    --求班级最高分和最低分(数值范围在统计中特别有用)

mysql> SELECT Max((IFNULL(JS,0)+IFNULL(Django,0)+IFNULL(OpenStack,0)))

                              最高分 FROM ExamResult;

+--------+

| 最高分 |

+--------+

|    294 |

+--------+

1 row in set

 

mysql> SELECT Min((IFNULL(JS,0)+IFNULL(Django,0)+IFNULL(OpenStack,0)))

                              最低分 FROM ExamResult;

+--------+

| 最低分 |

+--------+

|      0 |

+--------+

1 row in set

 

     --求购物表中单价最高的商品名称及价格

    SELECT id, MAX(price) FROM order_menu;--id和最高价商品是一个商品吗?(不是)

                   

    SELECT MAX(price) FROM order_menu;

 

        -- 注意:NULL 和所有的数计算都是NULL,所以需要用IFNULL将NULL转换为0!

    

           -- WITH ROLLUP的使用

 

        --<2> 统计分组后的组记录

 

--(7)重点:SELECT FROM WHERE GROUP BY HAVING ORDER BY

        -- MySQL在执行SQL语句时的执行顺序:

        -- FROM WHERE SELECT GROUP BY HAVING ORDER BY

        -- 分析:

            SELECT JS AS JS成绩 FROM ExamResult WHERE JS成绩 >70; ---- 不成功

            SELECT JS AS JS成绩 FROM ExamResult HAVING JS成绩 >90; --- 成功

 

--(8)limit 限制查询结果的数量

mysql> SELECT * FROM ExamResult limit 1; --显示第一条记录

+----+------+----+--------+-----------+

| id | name | JS | Django | OpenStack |

+----+------+----+--------+-----------+

|  1 | yuan | 98 |     98 |        98 |

+----+------+----+--------+-----------+

1 row in set

 

mysql> SELECT * FROM ExamResult limit 2,5; --跳过前两条显示接下来的五条纪录

+----+-------+------+--------+-----------+

| id | name  | JS   | Django | OpenStack |

+----+-------+------+--------+-----------+

|  3 | alex  |   59 |     59 |        62 |

|  4 | wusir |   88 |     89 |        82 |

|  5 | alvin |   88 |     98 |        67 |

|  6 | yuan  |   86 |    100 |        55 |

|  9 | lv    | NULL | NULL   | NULL      |

+----+-------+------+--------+-----------+

5 rows in set

 

mysql> SELECT * FROM ExamResult limit 2,2; ----跳过前两条显示接下来的二条纪录

+----+-------+----+--------+-----------+

| id | name  | JS | Django | OpenStack |

+----+-------+----+--------+-----------+

|  3 | alex  | 59 |     59 |        62 |

|  4 | wusir | 88 |     89 |        82 |

+----+-------+----+--------+-----------+

2 rows in set

 

--(9)使用正则表达式查询

        SELECT * FROM employee WHERE emp_name REGEXP '^yu';

 

        SELECT * FROM employee WHERE emp_name REGEXP 'yun$';

 

        SELECT * FROM employee WHERE emp_name REGEXP 'm{2}';

 

第五章 多表操作

                

外键约束

    --外键是指引用另外一张表中的一列或者多列,被引用的列应该具有主键约束或者唯一性约束。

        --外键用于建立和加强两个表数据之间的连接。

        --创建外键的表必须是InnoDB型,不能是临时表。因为在MySQL中InnoDB类型的表才支持外键。

 

       

创建外键

--每一个班主任会对应多个学生 , 而每个学生只能对应一个班主任

 

--不带外键约束的情况

--创建主表

mysql>CREATE TABLE ClassCharger(

       id TINYINT PRIMARY KEY AUTO_INCREMENT,

       name VARCHAR (20),

       age INT ,

       is_marriged BOOLEAN 

        );

       

        --SHOW CREATE TABLE 表名; --查看表创建方式

mysql> SHOW CREATE TABLE ClassCharger;

+--------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Table        | Create Table                                                                                                                                                                                                                                            |

+--------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| ClassCharger | CREATE TABLE `classcharger` (

  `id` tinyint(4) NOT NULL AUTO_INCREMENT,

  `name` varchar(20) DEFAULT NULL,

  `age` int(11) DEFAULT NULL,

  `is_marriged` tinyint(1) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 |

+--------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

1 row in set                               

        --可以看出BOOLEAN转换成TINYINT(1)

                                   

--查询表结构

mysql> DESC ClassCharger;

+-------------+-------------+------+-----+---------+----------------+

| Field       | Type        | Null | Key | Default | Extra          |

+-------------+-------------+------+-----+---------+----------------+

| id          | tinyint(4)  | NO   | PRI | NULL    | auto_increment |

| name        | varchar(20) | YES  |     | NULL    |                |

| age         | int(11)     | YES  |     | NULL    |                |

| is_marriged | tinyint(1)  | YES  |     | NULL    |                |

+-------------+-------------+------+-----+---------+----------------+

4 rows in set

 

--插入数据

mysql>INSERT INTO ClassCharger (name,age,is_marriged) VALUES ("冰冰",12,0),

                                                                                                                               ("丹丹",14,0),

                                                             ("歪歪",22,0),

                                                             ("姗姗",20,0),

                                                             ("小雨",21,0);

                                                                                                                               

--查询表内容

mysql> SELECT * FROM ClassCharger;

+----+------+-----+-------------+

| id | name | age | is_marriged |

+----+------+-----+-------------+

|  1 | 冰冰 |  12 |           0 |

|  2 | 丹丹 |  14 |           0 |

|  3 | 歪歪 |  22 |           0 |

|  4 | 姗姗 |  20 |           0 |

|  5 | 小雨 |  21 |           0 |

+----+------+-----+-------------+

5 rows in set

 

--创建子表

mysql>CREATE TABLE Student(

                         id INT PRIMARY KEY auto_increment,

                         name VARCHAR (20),

                         charger_id TINYINT   

                 ) ENGINE=INNODB;

              --ENGINE=INNODB为搜索引擎

                          

--查看表结构

ysql> DESC Student;

+------------+-------------+------+-----+---------+----------------+

| Field      | Type        | Null | Key | Default | Extra          |

+------------+-------------+------+-----+---------+----------------+

| id         | int(11)     | NO   | PRI | NULL    | auto_increment |

| name       | varchar(20) | YES  |     | NULL    |                |

| charger_id | tinyint(4)  | YES  |     | NULL    |                |

+------------+-------------+------+-----+---------+----------------+

3 rows in set           

 

--插入值

mysql>INSERT INTO Student(name,charger_id) VALUES ("alvin1",2),

                                                                                                       ("alvin2",4),

                                                                                                       ("alvin3",1),

                                                  ("alvin4",3),

                                                  ("alvin5",1),

                                                  ("alvin6",3),

                                                  ("alvin7",2);

                                                                                                      

--查看表内容

mysql> SELECT * FROM Student;

+----+--------+------------+

| id | name   | charger_id |

+----+--------+------------+

|  1 | alvin1 |          2 |

|  2 | alvin2 |          4 |

|  3 | alvin3 |          1 |

|  4 | alvin4 |          3 |

|  5 | alvin5 |          1 |

|  6 | alvin6 |          3 |

|  7 | alvin7 |          2 |

+----+--------+------------+

7 rows in set

 

mysql> DELETE FROM ClassCharger WHERE name="冰冰";

Query OK, 1 row affected

mysql> SELECT * FROM ClassCharger;

+----+------+-----+-------------+

| id | name | age | is_marriged |

+----+------+-----+-------------+

|  2 | 丹丹 |  14 |           0 |

|  3 | 歪歪 |  22 |           0 |

|  4 | 姗姗 |  20 |           0 |

|  5 | 小雨 |  21 |           0 |

+----+------+-----+-------------+

4 rows in set

                 --删除居然成功,可是 alvin3显示还是有班主任id=1的冰冰的;

mysql> INSERT student (name,charger_id) VALUES ("yuan",1);

Query OK, 1 row affected

mysql> SELECT * FROM Student;

+----+--------+------------+

| id | name   | charger_id |

+----+--------+------------+

|  1 | alvin1 |          2 |

|  2 | alvin2 |          4 |

|  3 | alvin3 |          1 |

|  4 | alvin4 |          3 |

|  5 | alvin5 |          1 |

|  6 | alvin6 |          3 |

|  7 | alvin7 |          2 |

|  8 | yuan   |          1 |

+----+--------+------------+

8 rows in set

                 --插入居然成功,可是班主任id=1的冰冰已经不在主表上了。

                

--含主键约束的情况

--创建另一主表

mysql>CREATE TABLE ClassCharger2(

       id TINYINT PRIMARY KEY AUTO_INCREMENT,

       name VARCHAR (20),

       age INT ,

       is_marriged boolean 

        ) ENGINE=INNODB;

       

--插入数据

mysql>INSERT INTO ClassCharger2 (name,age,is_marriged) VALUES ("冰冰",12,0),

                                                                                                                                ("丹丹",14,0),

                                                                                                                                ("歪歪",22,0),

                                                                                                                                ("姗姗",20,0),

                                                                                                                                ("小雨",21,0);

 

--创建另一子表(添加外键约束)

mysql>CREATE TABLE Student2(

                         id INT PRIMARY KEY auto_increment,

                         name VARCHAR (20),

                         charger_id TINYINT,FOREIGN KEY(charger_id) REFERENCES ClassCharger2(id)    

                 ) ENGINE=INNODB;

        --ENGINE=INNODB为搜索引擎

    --切记:作为外键一定要和关联主键的数据类型保持一致

        --[ADD CONSTRAINT FK_ID]FOREIGN KEY (charger_id) REFERENCES ClassCharger(id)

                          --FK_ID为外键名,不能加引号

mysql> SHOW CREATE TABLE Student2;

+----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Table    | Create Table                                                                                                                                                                                                                                                                                                                    |

+----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Student2 | CREATE TABLE `student2` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `name` varchar(20) DEFAULT NULL,

  `charger_id` tinyint(4) DEFAULT NULL,

  PRIMARY KEY (`id`),

  KEY `charger_id` (`charger_id`),

  CONSTRAINT `student2_ibfk_1` FOREIGN KEY (`charger_id`) REFERENCES `classcharger2` (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

+----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

1 row in set

     --可以看到外键创建成功,student2_ibfk_1 为外键名

         

--插入值

mysql>INSERT INTO Student2(name,charger_id) VALUES ("alvin1",2),

                                                                                                        ("alvin2",4),

                                                                                                        ("alvin3",1),

                                                   ("alvin4",3),

                                                   ("alvin5",1),

                                                   ("alvin6",3),

                                                   ("alvin7",2);

 

mysql> DELETE FROM ClassCharger2 WHERE name="冰冰";

1451 - Cannot delete or update a parent row: a foreign key constraint fails (`student_db`.`student2`, CONSTRAINT `student2_ibfk_1` FOREIGN KEY (`charger_id`) REFERENCES `classcharger2` (`id`))

--此时删除不成功,因为有外键约束。

--把'冰冰'在子表中所带的学生改成别的charger_id

mysql> UPDATE Student2 SET charger_id=4 WHERE id=3 OR id=5;

Query OK, 2 rows affected

Rows matched: 2  Changed: 2  Warnings: 0

--此时再删除'冰冰'

mysql> DELETE FROM ClassCharger2 WHERE name="冰冰";

Query OK, 1 row affected

--此时删除成功

mysql> mysql> DELETE FROM ClasINSERT student (name,charger_id) VALUES ("yuan",1);

1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'mysql> DELETE FROM ClasINSERT student (name,charger_id) VALUES ("yuan",1)' at line 1

--此时插入不成功,因为'冰冰'被删除。

 

--增加外键

  --语法:

        ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY(外键字段名) REFERENCES 外表表名(主键字段名);

  --示例

        ALTER TABLE student ADD CONSTRAINT FK_ID

                                                  FOREIGN KEY(charger_id)

                                                  REFERENCES ClassCharger(id);

                                           

--删除外键

  --语法:   

        ALTER TABLE 表名 DROP FOREIGN KEY 外键名;

  --示例:

        ALTER TABLE student DROP FOREIGN KEY abc;

 

操作关联表

关联关系

        1.多对一(在多对一的表关系中,应该将外键建在多的一方,否则会造成数据的冗余)

                 多对一是数据表中最常见的一种关系。比如,员工和部门之间的关系,一个部门可以有多个员工,而一个员工不能属于多个部门

                 也就是说,部门表中的一行在员工表中可以有许多匹配行,但员工表中的一行在部门表中只能有一个匹配行。

        2.多对多

            多对多也是数据表的一种关系。比如,学生与课程之间的关系,一个学生可以选择多门课程,当然一门课程也供多个学生选择

                 也就是说,学生表中的一行在课程表中可以有许多匹配行,课程表的一行在学生表也有许多匹配行。

                         --通常情况下,为了实现这种需求关系需要定义一张中间表(称为连接表),该表会存在两个外键,分别参照课程表和学生表。

                         --在多对多的关系中,需要注意的是,连接表的两个外键都是可以重复的,但是两个外键之间的关系是不能重复的,所以这两个外键又是连接表的联合主键。

        3.一对一

                 一对一关系在实际生活中比较常见,例如人与身份证之间就是一对一的关系,一个人对应一张身份证,一张身份证只能匹配一个人。那么,一对一的两张表如何建立外键?

                 首先,要分清主从关系。从表需要主表的存在才有意义,身份证需要人的存在才有意义。因此人为主表,身份证为从表。要在身份证表中建立外键。

                         --由实际经验可知,身份证中的外键必须是非空唯一的,因此通常会直接用从表(表身份证)中的主键作为外键。

                         --需要注意的是,这种关系在数据库中并不常见,因为一这种方式存储信息通常只会放在一个表中。

                         --在实际开发中,一对一关联关系可以应用于以下几个方面

                                  --(1)分割具有很多列的表;

                                  --(2)由于安全原因而隔离表的一部分。

                                  --(3)保存临时的数据,并且可以毫不费力地通过删除该表而删除这些数据。

INNODB支持的ON语句

 

--外键约束对子表的含义:如果在父表中找不到候选键,则不允许在子表上进行INSERT/UPDATE

 

--外键约束对父表的含义:在父表上进行UPDATE/DELETE以更新或删除在子表中有一条或多条对

                    -- 应匹配行的候选键时,父表的行为取决于:在定义子表的外键时指定的

                    -- ON UPDATE/ON DELETE子句

 

--InnoDB支持的四种方式

 

--CASCADE方式 在父表上UPDATE/DELETE记录时,同步UPDATE/DELETE掉子表的匹配记录

            --外键的级联删除:如果父表中的记录被删除,则子表中对应的记录自动被删除

 

     FOREIGN KEY (charger_id) REFERENCES ClassCharger(id) ON DELETE CASCADE

 

--SET NULL方式 在父表上update/delete记录时,将子表上匹配记录的列设为null

            -- 要注意子表的外键列不能为not null

 

     FOREIGN KEY (charger_id) REFERENCES ClassCharger(id)

                              ON DELETE SET NULL

                                                            

--Restrict方式 :拒绝主表删除或修改外键关联列。

 

--No action方式 在mysql中同Restrict,如果子表中有匹配的记录,则不允许对父表对应候选键

            -- 进行update/delete操作(了解)

 

多表查询

 

-- 准备两张表

-- company.employee

-- company.department

 

--创建员工表

mysql>CREATE TABLE employee(

      emp_id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,

      emp_name VARCHAR(50),

      age INT,

      dept_id INT

      );

--查询表结构

mysql> DESC employee;

+----------+-------------+------+-----+---------+----------------+

| Field    | Type        | Null | Key | Default | Extra          |

+----------+-------------+------+-----+---------+----------------+

| emp_id   | int(11)     | NO   | PRI | NULL    | auto_increment |

| emp_name | varchar(50) | YES  |     | NULL    |                |

| age      | int(11)     | YES  |     | NULL    |                |

| dept_id  | int(11)     | YES  |     | NULL    |                |

+----------+-------------+------+-----+---------+----------------+

4 rows in set

 

--插入值

mysql>INSERT INTO employee(emp_name,age,dept_id) VALUES ('A',19,200),

                                                                                                                      ('B',26,201),

                                                                                                                      ('C',30,201),

                                                                                                                      ('D',24,202),

                                                                                                                      ('E',20,200),

                                                                                                                      ('F',38,204);

 

--查看表内容

mysql> SELECT* FROM employee;

+--------+----------+-----+---------+

| emp_id | emp_name | age | dept_id |

+--------+----------+-----+---------+

|      1 | A        |  19 |     200 |

|      2 | B        |  26 |     201 |

|      3 | C        |  30 |     201 |

|      4 | D        |  24 |     202 |

|      5 | E        |  20 |     200 |

|      6 | F        |  38 |     204 |

+--------+----------+-----+---------+

6 rows in set

 

--创建部门表                                                                                                              

mysql>CREATE TABLE department(

       dept_id INT,

       dept_name VARCHAR(100)

      );

         

--查看表结构   

mysql> DESC department;

+-----------+--------------+------+-----+---------+-------+

| Field     | Type         | Null | Key | Default | Extra |

+-----------+--------------+------+-----+---------+-------+

| dept_id   | int(11)      | YES  |     | NULL    |       |

| dept_name | varchar(100) | YES  |     | NULL    |       |

+-----------+--------------+------+-----+---------+-------+

2 rows in set

 

--插入值

mysql>INSERT INTO department VALUES (200,'人事部'),

                                                                            (201,'技术部'),

                                                                            (202,'销售部'),

                                                                           (203,'财政部');

 

--查看表内容

mysql> SELECT * FROM department;

+---------+-----------+

| dept_id | dept_name |

+---------+-----------+

|     200 | 人事部    |

|     201 | 技术部    |

|     202 | 销售部    |

|     203 | 财政部    |

+---------+-----------+

4 rows in set

 

多表查询之连接查询

 

--1.笛卡尔积查询:两张表中一条一条对应的记录,m条记录和n条记录查询,最后得到m*n条,其中有很多错误数据。

 

mysql> SELECT * FROM employee,department;

 

      --上面这条命令等价于下面这条命令

      --SELECT employee.emp_id,employee.emp_name,employee.age,department.dept_id,department.dept_name FROM employee,department;

 

+--------+----------+------+---------+---------+-----------+

| emp_id | emp_name | age  | dept_id | dept_id | dept_name |

+--------+----------+------+---------+---------+-----------+

|      1 | A        |   19 |     200 |     200 | 人事部    |

|      1 | A        |   19 |     200 |     201 | 技术部    |

|      1 | A        |   19 |     200 |     202 | 销售部    |

|      1 | A        |   19 |     200 |     203 | 财政部    |

|      2 | B        |   26 |     201 |     200 | 人事部    |

|      2 | B        |   26 |     201 |     201 | 技术部    |

|      2 | B        |   26 |     201 |     202 | 销售部    |

|      2 | B        |   26 |     201 |     203 | 财政部    |

|      3 | C        |   30 |     201 |     200 | 人事部    |

|      3 | C        |   30 |     201 |     201 | 技术部    |

|      3 | C        |   30 |     201 |     202 | 销售部    |

|      3 | C        |   30 |     201 |     203 | 财政部    |

|      4 | D        |   24 |     202 |     200 | 人事部    |

|      4 | D        |   24 |     202 |     201 | 技术部    |

|      4 | D        |   24 |     202 |     202 | 销售部    |

|      4 | D        |   24 |     202 |     203 | 财政部    |

|      5 | E        |   20 |     200 |     200 | 人事部    |

|      5 | E        |   20 |     200 |     201 | 技术部    |

|      5 | E        |   20 |     200 |     202 | 销售部    |

|      5 | E        |   20 |     200 |     203 | 财政部    |

|      6 | F        |   38 |     204 |     200 | 人事部    |

|      6 | F        |   38 |     204 |     201 | 技术部    |

|      6 | F        |   38 |     204 |     202 | 销售部    |

|      6 | F        |   38 |     204 |     203 | 财政部    |

+--------+----------+------+---------+---------+-----------+

24 rows in set

 

--2.内连接:查询两张表中都有的关联数据,相当于利用条件从笛卡尔积结果中筛选出了正确的结果。

 

mysql> SELECT * FROM employee,department WHERE employee.dept_id = department.dept_id;

     

          --上面这条命令等价于下面这条命令

      --SELECT * FROM employee INNER JOIN department ON employee.dept_id = department.dept_id;

 

+--------+----------+-----+---------+---------+-----------+

| emp_id | emp_name | age | dept_id | dept_id | dept_name |

+--------+----------+-----+---------+---------+-----------+

|      1 | A        |  19 |     200 |     200 | 人事部    |

|      2 | B        |  26 |     201 |     201 | 技术部    |

|      3 | C        |  30 |     201 |     201 | 技术部    |

|      4 | D        |  24 |     202 |     202 | 销售部    |

|      5 | E        |  20 |     200 |     200 | 人事部    |

+--------+----------+-----+---------+---------+-----------+

5 rows in set

 

mysql>SELECT employee.emp_name,department.dept_name FROM employee,department

                                                              WHERE employee.dept_id=department.dept_id

                                                              AND employee.emp_name="A";

+----------+-----------+

| emp_name | dept_name |

+----------+-----------+

| A        | 人事部    |

+----------+-----------+

1 row in set

 

mysql>SELECT employee.emp_name,department.dept_name FROM department INNER JOIN employee

                                                              ON employee.dept_id=department.dept_id

                                                              AND employee.emp_name="A";

+----------+-----------+

| emp_name | dept_name |

+----------+-----------+

| A        | 人事部    |

+----------+-----------+

1 row in set

 

--3.外连接

 

  --(1)左外连接:在内连接的基础上增加左边有右边没有的结果

 

mysql>SELECT * FROM employee LEFT JOIN department ON employee.dept_id = department.dept_id;

 

+--------+----------+-----+---------+---------+-----------+

| emp_id | emp_name | age | dept_id | dept_id | dept_name |

+--------+----------+-----+---------+---------+-----------+

|      1 | A        |  19 |     200 |     200 | 人事部    |

|      2 | B        |  26 |     201 |     201 | 技术部    |

|      3 | C        |  30 |     201 |     201 | 技术部    |

|      4 | D        |  24 |     202 |     202 | 销售部    |

|      5 | E        |  20 |     200 |     200 | 人事部    |

|      6 | F        |  38 |     204 | NULL    | NULL      |

+--------+----------+-----+---------+---------+-----------+

6 rows in set

 

mysql>SELECT employee.emp_name,department.dept_name FROM employee LEFT JOIN department

                                                                                              ON employee.dept_id=department.dept_id;

+----------+-----------+

| emp_name | dept_name |

+----------+-----------+

| A        | 人事部    |

| B        | 技术部    |

| C        | 技术部    |

| D        | 销售部    |

| E        | 人事部    |

| F        | NULL      |

+----------+-----------+

6 rows in set

 

mysql>SELECT employee.emp_name,department.dept_name FROM department LEFT JOIN employee

                                                                                              ON employee.dept_id=department.dept_id;

+----------+-----------+

| emp_name | dept_name |

+----------+-----------+

| A        | 人事部    |

| E        | 人事部    |

| B        | 技术部    |

| C        | 技术部    |

| D        | 销售部    |

| NULL     | 财政部    |

+----------+-----------+

6 rows in set

                                                                                             

--(2)右外连接:在内连接的基础上增加右边有左边没有的结果

 

mysql>SELECT * FROM employee RIGHT JOIN department ON employee.dept_id = department.dept_id;

 

+--------+----------+------+---------+---------+-----------+

| emp_id | emp_name | age  | dept_id | dept_id | dept_name |

+--------+----------+------+---------+---------+-----------+

|      1 | A        |   19 |     200 |     200 | 人事部    |

|      5 | E        |   20 |     200 |     200 | 人事部    |

|      2 | B        |   26 |     201 |     201 | 技术部    |

|      3 | C        |   30 |     201 |     201 | 技术部    |

|      4 | D        |   24 |     202 |     202 | 销售部    |

| NULL   | NULL     | NULL | NULL    |     203 | 财政部    |

+--------+----------+------+---------+---------+-----------+

6 rows in set

 

 

--(3)全外连接:在内连接的基础上增加左边有右边没有的和右边有左边没有的结果

    -- mysql不支持全外连接 FULL JOIN

    -- mysql可以使用此种方式间接实现全外连接

   

mysql>SELECT * FROM employee RIGHT JOIN department ON employee.dept_id = department.dept_id

      UNION

      SELECT * FROM employee LEFT JOIN department ON employee.dept_id = department.dept_id;

 

+--------+----------+------+---------+---------+-----------+

| emp_id | emp_name | age  | dept_id | dept_id | dept_name |

+--------+----------+------+---------+---------+-----------+

|      1 | A        |   19 |     200 |     200 | 人事部    |

|      5 | E        |   20 |     200 |     200 | 人事部    |

|      2 | B        |   26 |     201 |     201 | 技术部    |

|      3 | C        |   30 |     201 |     201 | 技术部    |

|      4 | D        |   24 |     202 |     202 | 销售部    |

| NULL   | NULL     | NULL | NULL    |     203 | 财政部    |

|      6 | F        |   38 |     204 | NULL    | NULL      |

+--------+----------+------+---------+---------+-----------+

7 rows in set

 

      -- 注意 UNION与UNION ALL的区别:UNION会去掉相同的纪录

 

多表查询之复合条件连接查询

 

-- 查询员工年龄大于等于25岁的部门

mysql>SELECT DISTINCT department.dept_name

      FROM employee,department

      WHERE employee.dept_id = department.dept_id AND age>25;

+-----------+

| dept_name |

+-----------+

| 技术部    |

+-----------+

1 row in set    

--以内连接的方式查询employee和department表,并且以age字段的升序方式显示

mysql>SELECT employee.emp_id,employee.emp_name,employee.age,department.dept_name

      FROM employee,department

      WHERE employee.dept_id = department.dept_id

      ORDER BY age ASC;

+--------+----------+-----+-----------+

| emp_id | emp_name | age | dept_name |

+--------+----------+-----+-----------+

|      1 | A        |  19 | 人事部    |

|      5 | E        |  20 | 人事部    |

|      4 | D        |  24 | 销售部    |

|      2 | B        |  26 | 技术部    |

|      3 | C        |  30 | 技术部    |

+--------+----------+-----+-----------+

5 rows in set

 

多表查询之子查询

 

-- 子查询是将一个查询语句嵌套在另一个查询语句中。

-- 内层查询语句的查询结果,可以为外层查询语句提供查询条件。

-- 子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字

-- 还可以包含比较运算符:=、!=、>、<等

 

--1.带IN关键字的子查询

 

   ---查询employee表,但dept_id必须在department表中出现过

 

mysql>SELECT * FROM employee

            WHERE dept_id IN

                         (SELECT dept_id FROM department);

                        

+--------+----------+-----+---------+

| emp_id | emp_name | age | dept_id |

+--------+----------+-----+---------+

|      1 | A        |  19 |     200 |

|      2 | B        |  26 |     201 |

|      3 | C        |  30 |     201 |

|      4 | D        |  24 |     202 |

|      5 | E        |  20 |     200 |

+--------+----------+-----+---------+

5 rows in set

 

--2.带比较运算符的子查询

      --=、!=、>、>=、<、<=、<>

 

      --查询员工年龄大于等于25岁的部门

mysql> SELECT dept_id,dept_name FROM department

           WHERE dept_id IN

          (SELECT DISTINCT dept_id FROM employee WHERE age>=25);

+---------+-----------+

| dept_id | dept_name |

+---------+-----------+

|     201 | 技术部    |

+---------+-----------+

1 row in set    

 

--3.带EXISTS关键字的子查询

 

-- EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。

-- 而是返回一个真假值。Ture或False

-- 当返回Ture时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询

 

mysql> SELECT * FROM employee

               WHERE EXISTS

              (SELECT dept_name FROM department WHERE dept_id=203);

+--------+----------+-----+---------+

| emp_id | emp_name | age | dept_id |

+--------+----------+-----+---------+

|      1 | A        |  19 |     200 |

|      2 | B        |  26 |     201 |

|      3 | C        |  30 |     201 |

|      4 | D        |  24 |     202 |

|      5 | E        |  20 |     200 |

|      6 | F        |  38 |     204 |

+--------+----------+-----+---------+

6 rows in set

      --department表中存在dept_id=203,Ture

 

mysql> SELECT * FROM employee

                WHERE EXISTS

               (SELECT dept_name FROM department WHERE dept_id=205);

Empty set

      --department表中不存在dept_id=205,False

       

第六章事务与存储过程

MySQL事务

--1.事务的概念

    --指针对数据库的一组操作,它可以由一条或多条语句组成,同一事务的操作具备同步的特点;

    --如果其中有一条语句无法执行,那么所有的语句都不会执行。

        --也就是说,事务中的语句要么都被执行,要么都不执行。

--2.数据库事务命令

    --①开启事务:

            START TRANSACTION;

                 --事务开启之后就可以执行SQL语句,SQL语句执行成功后需要相应语句提交事务。

        --②提交事务:

                 COMMIT;

                 --在MySQL中直接书写SQL语句都是自动提交的,而事务中的操作都需要使用COMMIT语句手动提交。

                 --只有事务提交后其中的操作才会生效。

                 --如果不想提交事务可以使用相关语句取消事务(也称回滚)。

        --③回滚事务:

            ROLLBACK;

                 --ROLLBACK语句只能针对未提交的事务执行回滚操作,已提交的事务不能回滚。

        --④保留点:

                 SAVEPOINT

                 --事务处理中设置的临时占位符,可以对它发布回滚,与整个事务回滚不同。

--3.通过一个转账的案例演示如何使用事务

--创建库

mysql>CREATE DATABASE account_db;

--使用库

mysql>USE account_db;

--创建表

mysql>CREATE TABLE account_tb(

                         id INT PRIMARY KEY AUTO_INCREMENT,

                         name VARCHAR(20),

                         money FLOAT

                 )ENGINE=InnoDB;

--查看表结构

mysql>DESC account_tb;

+-------+-------------+------+-----+---------+----------------+

| Field | Type        | Null | Key | Default | Extra          |

+-------+-------------+------+-----+---------+----------------+

| id    | int(11)     | NO   | PRI | NULL    | auto_increment |

| name  | varchar(20) | YES  |     | NULL    |                |

| money | float       | YES  |     | NULL    |                |

+-------+-------------+------+-----+---------+----------------+

3 rows in set

--插入值

mysql>INSERT INTO account_tb(name,money) VALUES ('a',1000),

                                                                                                     ('b',1000);

--查看表内容                                                                                             

mysql>SELECT * FROM account_tb;

+----+------+-------+

| id | name | money |

+----+------+-------+

|  1 | a    |  1000 |

|  2 | b    |  1000 |

+----+------+-------+

2 rows in set                                                                                               

--事务一:首先开启一个事务,然后通过UPDATE语句将b账户的100元钱转给a账户,最后提交事务。

mysql>START TRANSACTION;

          UPDATE account_tb SET money=money-100 WHERE name='a';

          UPDATE account_tb SET money=money+100 WHERE name='b';

          COMMIT;

mysql>SELECT * FROM account_tb;

+----+------+-------+

| id | name | money |

+----+------+-------+

|  1 | a    |   900 |

|  2 | b    |  1100 |

+----+------+-------+

2 rows in set

 

--可以看出,通过事务成功地完成了转账。

--需要注意的是:以上两条UPADTE语句中如果任意一条语句出现错误就会导致事务不会提交。

--这样一来,如果在提交事务之前出现异常,事务中未提交的操作就会取消,因此就可以保证事务的同步性。

 

--事务二:

mysql>START TRANSACTION;

          INSERT INTO account_tb(name,money) VALUES ('c',1000);

          SELECT * FROM account_tb;

          COMMIT;

--保留点

mysql>START TRANSACTION;

          INSERT INTO account_tb(name,money) VALUES ('d',1000); 

          SAVEPOINT insert_d;

          SELECT * FROM account_tb;

+----+------+-------+

| id | name | money |

+----+------+-------+

|  1 | a    |   900 |

|  2 | b    |  1100 |

|  3 | c    |  1000 |

|  4 | d    |  1000 |

+----+------+-------+

4 rows in set

 

mysql>DELETE FROM account_tb WHERE id=4;

      SAVEPOINT delete1;

          SELECT * FROM account_tb;

+----+------+-------+

| id | name | money |

+----+------+-------+

|  1 | a    |   900 |

|  2 | b    |  1100 |

|  3 | c    |  1000 |

+----+------+-------+

mysql>DELETE FROM account_tb WHERE id=1;

      SAVEPOINT delete2;

          SELECT * FROM account_tb;

+----+------+-------+

| id | name | money |

+----+------+-------+

|  2 | b    |  1100 |

|  3 | c    |  1000 |

+----+------+-------+

2 rows in set   

mysql>ROLLBACK TO delete1;

Query OK, 0 rows affected

mysql>SELECT * FROM account_tb;

+----+------+-------+

| id | name | money |

+----+------+-------+

|  1 | a    |   900 |

|  2 | b    |  1100 |

|  3 | c    |  1000 |

+----+------+-------+

3 rows in set

--4.事务特性

        --①原子性(Atomicity)

                 --是指一个事务必须被视为一个不可分割的最小工作单元。

                 --只有事务中所有的数据库操作都执行成功,才算整个事务成功。

                 --事务中如果有任何一个SQL语句执行失败,已经执行成功的SQL语句也必须撤退,数据库的状态退回到执行事务前的状态。

        --②一致性(Consistency)

                 --事务前后数据的完整性必须保持一致。

                 --在事务执行之前数据库是符合数据完整性约束的,无论事务是否执行成功,事务结束后的数据库中的数据也应该是符合完整性约束的。

                 --在某一时间点,如果数据库中的所有记录都能保证满足当前数据库中的所有约束,则可以说当前的数据库是符合数据完整性约束的。

                 --比如删部门表前应该删掉关联员工(已经建立外键),如果数据库服务器发生错误,有一个员工没删掉,那么此时员工的部门表已经删除,那么就不符合完整性约束了,所以这样的数据库也就性能太差啦!

    --③隔离性(ISOLATION)

                 --事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。

        --④持久性(Durability)

                 --持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

--5.隔离性

        --将数据库设计为串行化程的数据库,让一张表在同一时间内只能有一个线程来操作。

        --如果将数据库设计为这样,那数据库的效率太低了。

        --所以数据库的设计这没有直接将数据库设计为串行化,而是为数据库提供多个隔离级别选项,使数据库的使用者可以根据使用情况自己定义到底需要什么样的隔离级别。

--6.事务的隔离级别

    --①READ UNCOMMITTED

                 --是事务中最低的级别,该级别下的事务可以读取到另一事务中未提交的数据,也被称为脏读(Dirty Read),这是特别危险的,要尽力防止。

            --MySQL的默认隔离级别是REPEATABLE READ (可重复性),该级别是可以避免脏读的。

                 --因此,为了演示需要将b账户中事务的隔离级别设置为READ UNCOMMITTED(读未提交)。

                   SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

--演示

    --a账户 1000

        --b账户 1000

--创建表

mysql>CREATE TABLE account_tb1(

                         id INT PRIMARY KEY AUTO_INCREMENT,

                         name VARCHAR(20),

                         money FLOAT

                 )ENGINE=InnoDB;

--查看表结构

mysql>DESC account_tb1;     

+-------+-------------+------+-----+---------+----------------+

| Field | Type        | Null | Key | Default | Extra          |

+-------+-------------+------+-----+---------+----------------+

| id    | int(11)     | NO   | PRI | NULL    | auto_increment |

| name  | varchar(20) | YES  |     | NULL    |                |

| money | float       | YES  |     | NULL    |                |

+-------+-------------+------+-----+---------+----------------+

3 rows in set   

--插入值

mysql>INSERT INTO account_tb1(name,money) VALUES ('a',1000),

                                                                                                      ('b',1000);     

--查看表内容

mysql>SELECT * FROM account_tb1;

+----+------+-------+

| id | name | money |

+----+------+-------+

|  1 | a    |  1000 |

|  2 | b    |  1000 |

+----+------+-------+

2 rows in set                                                                                               

--两个命令行窗口模拟a账户、b账户

--a账户窗口:

mysql>START TRANSACTION;

          UPDATE account_tb1 SET money=money-100 WHERE name='a';

          UPDATE account_tb1 SET money=money+100 WHERE name='b';

--注意:此时不要提交事务,如果提交事务,就无法演示脏读的情况。

--b账户窗口:

mysql>START TRANSACTION;

          SELECT * FROM account_tb1; --此时看到a=900 b=1100

          COMMIT;

--a账户窗口:

mysql>ROLLBACK;  

--b账户窗口:

mysql>START TRANSACTION;

          SELECT * FROM account_tb1; --此时看到a=1000 b=1000

          COMMIT;

--注意:为了防止脏读发生,可以将事务的隔离级别设置为READ COMMITTED(读提交)

          SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

         

        --②不可重复读(NON-REPEATABLE READ)

                 --在一个事务内读取表中的某一行数据,多次读取结果不同。

                 --(一个事务读取到了另一个事务已经提交的数据——增加记录、删除记录。修改记录)。

                 --在某些情况下这不是问题,但在另一些情况下就是问题。

--演示

    --a账户 1000

        --b账户 1000

--创建表

mysql>CREATE TABLE account_tb2(

                         id INT PRIMARY KEY AUTO_INCREMENT,

                         name VARCHAR(20),

                         money FLOAT

                 )ENGINE=InnoDB;

--插入值

mysql>INSERT INTO account_tb2(name,money) VALUES ('a',1000),

                                                                                                      ('b',1000);               

--两个命令行窗口模拟a账户、b账户

--a账户窗口:

mysql>START TRANSACTION;

          UPDATE account_tb SET money=money-100 WHERE name='a';        

          SELECT * FROM account_tb2;

--b账户窗口:

mysql>START TRANSACTION;

          SELECT * FROM account_tb2; --此时看到a=900 b=1000

          COMMIT;

--对比b账户两次查询结果可以发现,两次查询结果是不一致的,实际上这种操作是没有错的,但是如果在银行统计报表时,     

--这种情况不符合需求的,因为我们不希望在一个事务中看到的查询结果不一致,这就是不可重复读。

        --③虚读(PHANTOM READ)

        --是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

                 --(一个事务读取到了另一个事务已经提交的数据---增加记录、删除记录).

                 --在某写情况下并不是问题,在另一些情况下就是问题。

--演示

    --a账户 1000

        --b账户 1000

--创建表

mysql>CREATE TABLE account_tb3(

                         id INT PRIMARY KEY AUTO_INCREMENT,

                         name VARCHAR(20),

                         money FLOAT

                 )ENGINE=InnoDB;

--插入值

mysql>INSERT INTO account_tb3(name,money) VALUES ('a',1000),

                                                                                                      ('b',1000);

--两个命令行窗口模拟a账户、b账户

--a账户窗口:

mysql>START TRANSACTION   

          SELECT * FROM account_tb3;

          INSERT INTO account_tb3(name,money) VALUES ('c',1000);

--b账户窗口:

mysql>START TRANSACTION;

          SELECT * FROM account_tb3; --此时看到a b c 三个账号

          COMMIT;    

        --④可串行化(SEPIALIZABLE)

           --是事务的最高级别,它在每个读的数据行上加上锁,使之不可能互相冲突,因此会出现大量的超时现象。

           --(通常情况下是不会使用这种隔离级别的)。

--7.四种隔离级别

        --四个隔离级别:

          --Serializable:可避免脏读、不可重复读、虚读情况的发生。(串行化)

          --Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)不可以避免虚读

          --Read committed:可避免脏读情况发生(读已提交)

          --Read uncommitted:最低级别,以上情况均无法保证。(读未提交)

          --安全性考虑:Serializable>Repeatable read>Read committed>Read uncommitted

          --数据库效率:Read uncommitted>Read committed>Repeatable read>Serializable

          --一般情况下,我们会使用Repeatable read、Read committed mysql数据库默认的数据库隔离级别Repeatable read

    --mysql中设置数据库的隔离级别语句:   

                 SET [GLOBAL/SESSION] TRANSACTION ISOLATION LEVEL xxxx;

                 --如果使用global则修改的是数据库的默认隔离级别,所有新开的窗口的隔离级别继承自这个默认隔离级别如果使用session修改,则修改的是当前客户端的隔离级别,和数据库默认隔离级别无关。当前的客户端是什么隔离级别,就能防止什么隔离级别问题,和其他客户端是什么隔离级别无关。

        --mysql中设置数据库的隔离级别语句:

                 SELECT @@tx_isolation;

                

MySQL存储过程的创建及调用

阅读目录:MySQL存储过程_创建-调用-参数

存储过程:SQL中的“脚本”

    1.创建存储过程

    2.调用存储过程

    3.存储过程体

    4.语句块标签

存储过程的参数

    1.IN:向过程里传参

    2.OUT:过程向外传参值

    3.INOUT:IN AND OUT

-- SQL语句:先编译后执行

存储过程(Stored Procedure):

  一组可编程的函数,是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。

 

优点(为什么要用存储过程?):

  ①将重复性很高的一些操作,封装到一个存储过程中,简化了对这些SQL的调用

  ②批量处理:SQL+循环,减少流量,也就是"跑批"

  ③统一接口,确保数据的安全

相对于oracle数据库来说,MySQL的存储过程相对功能较弱,使用较少。

 

一、存储过程的创建和调用

  >存储过程就是具有名字的一段代码,用来完成一个特定的功能。

  >创建的存储过程保存在数据库的数据字典中。

 

-- 1、创建存储过程

--基本语法

CREATE

    [DEFINER = { user | CURRENT_USER }]

 PROCEDURE sp_name ([proc_parameter[,...]])

    [characteristic ...] routine_body

--CREATE PROCEDURE为用来创建存储过程的关键字

--sp_name为存储过程的名称

--proc_parameter为指定存储过程的参数列表

 

proc_parameter:

    [ IN | OUT | INOUT ] param_name type

--IN表示输入参数,OUT表示输出参数,INOUT表示既可以输入也可以输出

--param_name表示参数名称

--type表示参数的类型,他可以是MySQL数据库中的任意类型,如INT等

 

--characteristic用于存储过程的特性。

characteristic:

    COMMENT 'string'

  | LANGUAGE SQL

  | [NOT] DETERMINISTIC

  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }

  | SQL SECURITY { DEFINER | INVOKER }

 

routine_body:

  Valid SQL routine statement

--routine_body是SQL代码的内容,可以用BEGIN...END来表示SQL代码的开始和结束

 

[begin_label:] BEGIN

  [statement_list]

    ……

END [end_label]

 

 

-- 创建数据库、数据表用于示例操作

mysql> CREATE DATABASE db1;

mysql> USE db1; 

--创建表 

mysql> CREATE TABLE Student(

                                  id INTEGER PRIMARY KEY auto_increment,

                                  name VARCHAR(20) NOT NULL,

                                  grade FLOAT,

                                  gender CHAR(2)

                 );

--插入数据

mysql> INSERT INTO Student(name,grade,gender)VALUES('TOM',60,'男'),

                                                                                                        ('Jack',70,'男'),

                                                                                                        ('ROSE',90,'女'),

                                                                                                        ('Lucy',100,'女');

 

--示例:创建一个存储过程,用于查看Student表

 

mysql> DELIMITER //  --将语句的结束符号从分号;临时改为两个//(可以是自定义)

mysql> CREATE PROCEDURE select_Student()

           BEGIN

       SELECT * FROM Student;

       END //

Query OK, 0 rows affected

mysql> DELIMITER;  --将语句的结束符号恢复为分号

 

--解析:

  --默认情况下,存储过程和默认数据库相关联,如果想指定存储过程创建在某个特定的数据库下,那么在过程名前面加数据库名做前缀;

  --在定义过程时,使用DELIMITER // 命令将语句的结束符号从分号 ; 临时改为两个//,使得过程体中使用的分号被直接传递到服务器,而不会被客户端(如mysql)解释。

 

-- 2、调用存储过程:CALL sp_name[(传参)];

 

mysql> SELECT * FROM Student;

+----+------+-------+--------+

| id | name | grade | gender |

+----+------+-------+--------+

|  1 | TOM  |    60 | 男     |

|  2 | Jack |    70 | 男     |

|  3 | ROSE |    90 | 女     |

|  4 | Lucy |   100 | 女     |

+----+------+-------+--------+

4 rows in set

 

mysql> CALL select_Student;

+----+------+-------+--------+

| id | name | grade | gender |

+----+------+-------+--------+

|  1 | TOM  |    60 | 男     |

|  2 | Jack |    70 | 男     |

|  3 | ROSE |    90 | 女     |

|  4 | Lucy |   100 | 女     |

+----+------+-------+--------+

4 rows in set

 

Query OK, 0 rows affected

 

3、存储过程体

  >存储过程体包含了在过程调用时必须执行的语句,例如:DML、DDL语句,if-then-else和while-do语句、声明变量的declare语句等

  >过程体格式:以BEGIN开始,以END结束(可嵌套)

 

BEGIN

  BEGIN

    BEGIN

      statements;

    END

  END

END

 

-- 注意:每个嵌套块及其中的每条语句,必须以分号结束,表示过程体结束的begin-end块(又叫做复合语句compound statement),则不需要分号。

 

4、为语句块贴标签

[begin_label:] BEGIN

  [statement_list]

END [end_label]

例如:

label1: BEGIN

  label2: BEGIN

    label3: BEGIN

      statements;

    END label3 ;

  END label2;

END label1

 

标签有两个作用:

  ①增强代码的可读性

  ②在某些语句(例如:leave和iterate语句),需要用到标签

 

二、存储过程的参数

  存储过程可以有0个或多个参数,用于存储过程的定义。

3种参数类型:

  IN输入参数:表示调用者向过程传入值(传入值可以是字面量或变量)

  OUT输出参数:表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)

  INOUT输入输出参数:既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量)

 

--1、IN输入参数

mysql> DELIMITER $$

mysql> CREATE PROCEDURE in_param(IN p_in INT)

                 BEGIN

                         SELECT p_in;

                         SET p_in=2;

                         SELECT p_in;

                 END $$

mysql> DELIMITER ;

 

mysql> SET @p_in=1;

 

mysql> CALL in_param(@p_in);

+------+

| p_in |

+------+

|    1 |

+------+

1 row in set

 

+------+

| P_in |

+------+

|    2 |

+------+

1 row in set

 

Query OK, 0 rows affected

 

mysql> SELECT @p_in;

+-------+

| @p_in |

+-------+

|     1 |

+-------+

1 row in set

 

-- 以上可以看出,p_in在存储过程中被修改,但并不影响@p_in的值,因为前者为局部变量、后者为全局变量。

 

--2、OUT输出参数

 

mysql> DELIMITER //

mysql> CREATE PROCEDURE out_param(out p_out INT)

                 BEGIN

                         SELECT p_out;

                         SET p_out=2;

                         SELECT p_out;

                 END //

mysql> DELIMITER ;

 

 

mysql> SET @p_out=1;

 

mysql> CALL out_param(@p_out);

+-------+

| p_out |

+-------+

| NULL  |

+-------+

1 row in set

             -- 因为out是向调用者输出参数,不接收输入的参数,所以存储过程里的p_out为null

+-------+

| p_out |

+-------+

|     2 |

+-------+

1 row in set

 

Query OK, 0 rows affected

 

mysql> SELECT @p_out;

+--------+

| @p_out |

+--------+

|      2 |

+--------+

-- 调用了out_param存储过程,输出参数,改变了p_out变量的值

 

 

--3、INOUT输入参数

 

mysql> DELIMITER $$

mysql> CREATE PROCEDURE inout_param(INOUT p_inout INT)

                 BEGIN

                         SELECT p_inout;

                         SET p_inout=2;

                         SELECT p_inout;

                 END $$

mysql> DELIMITER ;

 

mysql> SET @p_inout=1;

 

mysql> CALL inout_param(@p_inout);

+---------+

| p_inout |

+---------+

|       1 |

+---------+

1 row in set

 

+---------+

| p_inout |

+---------+

|       2 |

+---------+

1 row in set

 

Query OK, 0 rows affected

 

mysql> SELECT @p_inout;

+----------+

| @p_inout |

+----------+

|        2 |

+----------+

 

--调用了inout_param存储过程,接受了输入的参数,也输出参数,改变了变量

 

注意:

  ①如果过程没有参数,也必须在过程名后面写上小括号

    例:CREATE PROCEDURE sp_name ([proc_parameter[,...]]) ……

  ②确保参数的名字不等于列的名字,否则在过程体中,参数名被当做列名来处理

建议:

  >输入值使用in参数;

  >返回值使用out参数;

  >inout参数就尽量的少用。

 

触发器简介

触发器是一个特殊的存储过程,执行存储过程需要使用CALL语句来调用,但是触发器的执行不需要用CALL语句调用,也不需要手工启动,只要当一个预定义的事件发生时,就会被MySQL自动调用。

比如当对表进行INSERT,DELETE或UPDATE操作时就会激活它。

触发器可以查询数据表,而且可以包含复杂的SQL语句,主要用于复杂的业务规则或要求。

 

--1创建只包含一个执行语句的触发器

mysql>CREATE TRIGGER trigger_name trigger_time trigger_event ON tb_name FOR RACH ROW trigger_stmt

 

trigger_name:触发器名称,用户自行指定;

trigger_time:触发时机,取值为 BEFORE 或 AFTER;

trigger_event:触发事件,取值为 INSERT、UPDATE 或 DELETE;

tb_name:建立触发器的表名,即在哪张表上建立触发器;

trigger_stmt:触发器程序体,可以是一句SQL语句,或者用 BEGIN 和 END 包含的多条语句。

由此可见,可以建立6种触发器,即:BEFORE INSERT、BEFORE UPDATE、BEFORE DELETE、AFTER INSERT、AFTER UPDATE、AFTER DELETE。

另外有一个限制是不能同时在一个表上建立2个相同类型的触发器,因此在一个表上最多建立6个触发器。

 

--2.查看触发器

查看触发器是指查看数据库中存在的触发器的定义、状态和语法信息等。

本节介绍两种查看触发器的方法,分别为SHOW TRIGGERS语句查看和在TRIGGERS表中查看触发器信息。

        2.1用SHOW TRIGGERS语句查看

语句如下:

        SHOW TRIGGERS;

 

直接使用该条语句查看的信息可能有些混乱,可以在该条语句之后加上”\G”显示信息会比较有条理;

        2.2在triggers表中查看触发器信息

在MySQL中,所有的触发器的定义都存在于INFORMATION_SCHEMA数据库的triggers表中,可以通过查询命令SELECT来查看,具体语法如下:

        SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE condition;

 

--3.删除触发器

使用DROP TRIGGERS语句可以删除触发器,基本语法如下:

        DROP TRIGGERS [schema_name.]trigger_name

其中,schema_name是数据库的名称,是可选的。如果省略了schema,将从当前数据库中舍弃触发程序。trigger_name是要删除的触发器的名称。

 

第七章视图

 

MySQL视图

 

一、创建视图

二、查看视图

三、视图的更改

  1、CREATE OR REPLACE VIEW

  2、ALTER

  3、DML

  4、DROP

四、使用WITH CHECK OPTION约束

  嵌套视图

五、定义视图时的其他选项:ALGORITHM、DEFINER、SQL SECURITY视图权限

六、应用案例——视图的应用

Q:什么是视图?视图是干什么用的?

A:视图(VIEW)是一种虚拟存在的表,是一个逻辑表,本身并不包含数据。作为一个SELECT语句保存在数据字典中的。

  通过视图,可以展现基表的部分数据;视图数据来自定义视图的查询中使用的表,使用视图动态生成。

基表:用来创建视图的表叫做基表BASE TABLE

Q:为什么要使用视图?

A:因为视图的诸多优点,如下

  1)简单:使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果集。

  2)安全:使用视图的用户只能访问他们被允许查询的结果集,对表的权限管理并不能限制到某个行某个列,但是通过视图就可以简单的实现。

  3)数据独立:一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。

总而言之,使用视图的大部分情况是为了保障数据安全性,提高查询效率。

 

--一、创建视图

CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]

    VIEW view_name [(column_list)]

    AS SELECT_statement

   [WITH [CASCADED | LOCAL] CHECK OPTION]

--1)OR REPLACE:表示替换已有视图

--2)ALGORITHM:表示视图选择算法,默认算法是UNDEFINED(未定义的):MySQL自动选择要使用的算法 ;MERGE合并;TEMPTABLE临时表

--3)SELECT_statement:表示select语句

--4)[WITH [CASCADED | LOCAL] CHECK OPTION]:表示视图在更新时保证在视图的权限范围之内

  --CASCADE是默认值,表示更新视图的时候,要满足视图和表的相关条件

  --LOCAL表示更新视图的时候,要满足该视图定义的一个条件即可

TIPS:推荐使用WHIT [CASCADED|LOCAL] CHECK OPTION选项,可以保证数据的安全性

基本格式:

  CREATE VIEW <视图名称>[(column_list)]

       AS SELECT语句

       WITH CHECK OPTION;

1、在单表上创建视图

mysql>CREATE DATABASE student_db;

Query OK, 1 row affected

mysql>USE student_db;

Database changed

--创建表

mysql>CREATE TABLE student_tb(

                                  s_id INTEGER(3) PRIMARY KEY auto_increment,

                                  name VARCHAR(20),

                                  sex CHAR(2),

                                  Math FLOAT,

                                  Chinese FLOAT,

                                  English FLOAT

        );

--插入数据

mysql>INSERT INTO student_tb (name,sex,Math,Chinese,English)VALUES('Tom','男',80,78,75),

                                                                                                                                    ('Mary','女',90,88,65),

                                                                                                                                        ('Lucky','男',80,75,70),

                                                                                                                                    ('Tim','男',85,70,77),

                                                                                                                                    ('Rose','女',83,86,76),

                                                                                                                                    ('Lucy','女',84,85,89),

                                                                                                                                    ('Jack','男',85,83,88),

                                                                                                                                    ('Mimi','女',89,72,86);

--创建视图

mysql> CREATE VIEW view_student(学号,名字,性别,数学,语文,英语)

                 AS

                 SELECT s_id,name,sex,Math,Chinese,English FROM student_tb

                 WITH CHECK OPTION;

Query OK, 0 rows affected

--使用DESCRIBE 语句查看视图

--DESCRIBE 视图名; -- DESCRIBE可以简写为DESC

mysql> DESC view_student;

+-------+-------------+------+-----+---------+-------+

| Field | Type        | Null | Key | Default | Extra |

+-------+-------------+------+-----+---------+-------+

| 学号  | int(3)      | NO   |     | 0       |       |

| 名字  | varchar(20) | YES  |     | NULL    |       |

| 性别  | char(2)     | YES  |     | NULL    |       |

| 数学  | float       | YES  |     | NULL    |       |

| 语文  | float       | YES  |     | NULL    |       |

| 英语  | float       | YES  |     | NULL    |       |

+-------+-------------+------+-----+---------+-------+

6 rows in set

 

mysql> SELECT * FROM  view_student;

+------+-------+------+------+------+------+

| 学号 | 名字  | 性别 | 数学 | 语文 | 英语 |

+------+-------+------+------+------+------+

|    1 | Tom   | 男   |   80 |   78 |   75 |

|    2 | Mary  | 女   |   90 |   88 |   65 |

|    3 | Lucky | 男   |   80 |   75 |   70 |

|    4 | Tim   | 男   |   85 |   70 |   77 |

|    5 | Rose  | 女   |   83 |   86 |   76 |

|    6 | Lucy  | 女   |   84 |   85 |   89 |

|    7 | Jack  | 男   |   85 |   83 |   88 |

|    8 | Mimi  | 女   |   89 |   72 |   86 |

+------+-------+------+------+------+------+

8 rows in set

 

2、在多表上创建视图

--进入数据库

mysql>USE student_db;

Database changed

--创建表

mysql>CREATE TABLE student_inf_tb(

                                  s_id INTEGER(3) PRIMARY KEY auto_increment,

                                  class VARCHAR(50),

                                  addr CHAR(100)

        );

--插入数据

mysql>INSERT INTO student_inf_tb(class,addr)VALUES('1班','上海'),

                                                                                                       ('2班','北京'),

                                                                                                       ('3班','重庆'),

                                                                                                  ('2班','四川'),

                                                                                                  ('3班','安徽'),

                                                                                                  ('2班','江苏'),

                                                                                                  ('3班','海南'),

                                                                                                  ('1班','湖北');

--创建视图                                                                                 

mysql> CREATE VIEW view_student_class(学号,名字,班级,地址)

                 AS

                 SELECT student_tb.s_id,student_tb.name,student_inf_tb.class,student_inf_tb.addr

                 FROM student_tb,student_inf_tb

                 WHERE student_tb.s_id=student_inf_tb.s_id;

Query OK, 0 rows affected

 

mysql> SELECT * FROM view_student_class;

+------+-------+------+------+

| 学号 | 名字  | 班级 | 地址 |

+------+-------+------+------+

|    1 | Tom   | 1班  | 上海 |

|    2 | Mary  | 2班  | 北京 |

|    3 | Lucky | 3班  | 重庆 |

|    4 | Tim   | 2班  | 四川 |

|    5 | Rose  | 3班  | 安徽 |

|    6 | Lucy  | 2班  | 江苏 |

|    7 | Jack  | 3班  | 海南 |

|    8 | Mimi  | 1班  | 湖北 |

+------+-------+------+------+

8 rows in set

 

视图将我们不需要的数据过滤掉,将相关的列名用我们自定义的列名替换。视图作为一个访问接口,不管基表的表结构和表名有多复杂。

   如果创建视图时不明确指定视图的列名,那么列名就和定义视图的SELECT子句中的列名完全相同;

  如果显式的指定视图的列名就按照指定的列名。

注意:显示指定视图列名,要求视图名后面的列的数量必须匹配SELECT子句中的列的数量。

 

--二、查看视图

-- 1、使用SHOW CREATE VIEW语句

查看视图信息

 

/* 解决显示不了中文的方法

mysql> set character_set_client=gbk;

mysql> set character_set_connection=gbk;

mysql> set character_set_results=gbk;

*/

 

mysql> SHOW CREATE VIEW view_student\G;

*************************** 1. row ***************************

                View: view_student

         Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `view_student` AS select `student_tb`.`s_id` AS `学号`,`student_tb`.`name` AS `名字`,`student_tb`.`sex` AS `性别`,`student_tb`.`Math` AS `数学`,`student_tb`.`Chinese` AS `语文`,`student_tb`.`English` AS `英语` from `student_tb` WITH CASCADED CHECK OPTION

character_set_client: utf8

collation_connection: utf8_general_ci

1 row in set (0.00 sec)

--2、视图一旦创建完毕,就可以像一个普通表那样使用,视图主要用来查询

mysql> SELECT * FROM view_student;

+------+-------+------+------+------+------+

| 学号 | 名字  | 性别 | 数学 | 语文 | 英语 |

+------+-------+------+------+------+------+

|    1 | Tom   | 男   |   80 |   78 |   75 |

|    2 | Mary  | 女   |   90 |   88 |   65 |

|    3 | Lucky | 男   |   80 |   75 |   70 |

|    4 | Tim   | 男   |   85 |   70 |   77 |

|    5 | Rose  | 女   |   83 |   86 |   76 |

|    6 | Lucy  | 女   |   84 |   85 |   89 |

|    7 | Jack  | 男   |   85 |   83 |   88 |

|    8 | Mimi  | 女   |   89 |   72 |   86 |

+------+-------+------+------+------+------+

8 rows in set

3、有关视图的信息记录在information_schema数据库中的views表中

mysql> SELECT * FROM information_schema.views

       WHERE TABLE_NAME='view_student'\G;

*************************** 1. row ***************************

       TABLE_CATALOG: def

        TABLE_SCHEMA: s3

          TABLE_NAME: view_student

     VIEW_DEFINITION: select `s3`.`student_tb`.`s_id` AS `学号`,`s3`.`student_tb`.`name` AS `名字`,`s3`.`student_tb`.`sex` AS `性别`,`s3`.`student_tb`.`Math` AS `数学`,`s3`.`student_tb`.`Chinese` AS `语文`,`s3`.`student_tb`.`English` AS `英语` from `s3`.`student_tb`

        CHECK_OPTION: CASCADED

        IS_UPDATABLE: YES

             DEFINER: root@localhost

       SECURITY_TYPE: DEFINER

CHARACTER_SET_CLIENT: utf8

COLLATION_CONNECTION: utf8_general_ci

1 row in set (0.01 sec)

 

--三、视图的更改

--1、使用CREATE OR REPLACE VIEW语句修改视图

CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]

    VIEW view_name [(column_list)]

    AS SELECT_statement

   [WITH [CASCADED | LOCAL] CHECK OPTION]

基本格式:

  CREATE OR REPLACE VIEW view_name AS select语句;

--在视图存在的情况下可对视图进行修改,视图不在的情况下可创建视图;

  --例 使用CREATE OR REPLACE VIEW 语句修改view_student视图

 mysql> CREATE OR REPLACE VIEW view_student AS SELECT * FROM student_tb;

 Query OK, 0 rows affected

--2、ALTER语句修改视图

ALTER [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]

      [DEFINER = { user | CURRENT_USER }]

      [SQL SECURITY { DEFINER | INVOKER }]

          VIEW view_name [(column_list)]

          AS SELECT_statement

     [WITH [CASCADED | LOCAL] CHECK OPTION]

       

        --注意:修改视图是指修改数据库中已存在的表的定义,当基表的某些字段发生改变时,可以通过修改视图来保持视图和基本表之间一致

--3、DML操作更新视图

  因为视图本身没有数据,因此对视图进行的DML操作最终都体现在基表中

mysql> CREATE VIEW v_student AS SELECT * FROM student_tb;

Query OK, 0 rows affected

mysql> SELECT * FROM v_student;

+------+-------+-----+------+---------+---------+

| s_id | name  | sex | Math | Chinese | English |

+------+-------+-----+------+---------+---------+

|    1 | Tom   | 男  |   80 |      78 |      75 |

|    2 | Mary  | 女  |   90 |      88 |      65 |

|    3 | Lucky | 男  |   80 |      75 |      70 |

|    4 | Tim   | 男  |   85 |      70 |      77 |

|    5 | Rose  | 女  |   83 |      86 |      76 |

|    6 | Lucy  | 女  |   84 |      85 |      89 |

|    7 | Jack  | 男  |   85 |      83 |      88 |

|    8 | Mimi  | 女  |   89 |      72 |      86 |

+------+-------+-----+------+---------+---------+

8 rows in set

mysql> UPDATE v_student SET name='小六' WHERE s_id='1';

Query OK, 1 row affected

Rows matched: 1  Changed: 1  Warnings: 0

 

mysql> SELECT * FROM student_tb;

+------+-------+-----+------+---------+---------+

| s_id | name  | sex | Math | Chinese | English |

+------+-------+-----+------+---------+---------+

|    1 | 小六  | 男  |   80 |      78 |      75 |

|    2 | Mary  | 女  |   90 |      88 |      65 |

|    3 | Lucky | 男  |   80 |      75 |      70 |

|    4 | Tim   | 男  |   85 |      70 |      77 |

|    5 | Rose  | 女  |   83 |      86 |      76 |

|    6 | Lucy  | 女  |   84 |      85 |      89 |

|    7 | Jack  | 男  |   85 |      83 |      88 |

|    8 | Mimi  | 女  |   89 |      72 |      86 |

+------+-------+-----+------+---------+---------+

8 rows in set

 

当然,视图的DML操作,不是所有的视图都可以做DML操作。

有下列内容之一,视图不能做DML操作:

  ①SELECT子句中包含DISTINCT

  ②SELECT子句中包含组合函数

  ③SELECT语句中包含GROUP BY子句

  ④SELECT语句中包含ORDER BY子句

  ⑤SELECT语句中包含UNION 、UNION ALL等集合运算符

  ⑥WHERE子句中包含相关子查询

  ⑦FROM子句中包含多个表

  ⑧如果视图中有计算列,则不能更新

  ⑨如果基表中有某个具有非空约束的列未出现在视图定义中,则不能做INSERT操作

--4、DROP删除视图

  删除视图是指删除数据库中已存在的视图,删除视图时,只能删除视图的定义,不会删除数据,也就是说不动基表:

DROP VIEW [IF EXISTS]  

view_name [, view_name1] ...

[RESTRICT | CASCADE]

mysql> DROP VIEW v_student;

Query OK, 0 rows affected

   如果视图不存在,则抛出异常;使用IF EXISTS选项使得删除不存在的视图时不抛出异常。

  

--四、使用WITH CHECK OPTION约束

对于可以执行DML操作的视图,定义时可以带上WITH CHECK OPTION约束

作用:

  对视图所做的DML操作的结果,不能违反视图的WHERE条件的限制。

示例:创建视图,包含英语成绩大于80分的所有学生

mysql> CREATE VIEW v_student

                 AS

                 SELECT * FROM student_tb

                 WHERE English > 80

                 WITH CHECK OPTION;

Query OK, 0 rows affected

 

mysql> SELECT * FROM v_student;

+------+------+-----+------+---------+---------+

| s_id | name | sex | Math | Chinese | English |

+------+------+-----+------+---------+---------+

|    6 | Lucy | 女  |   84 |      85 |      89 |

|    7 | Jack | 男  |   85 |      83 |      88 |

|    8 | Mimi | 女  |   89 |      72 |      86 |

+------+------+-----+------+---------+---------+

3 rows in set

 

如果不加WITH CHECK OPTION会因为违反了视图中的WHERE English > 80子句,而抛出异常;

利用WITH CHECK OPTION约束限制,保证更新视图是在该视图的权限范围之内。

 

嵌套视图:定义在另一个视图的上面的视图

mysql> CREATE VIEW v_ear_student

                 AS

                 SELECT * FROM v_student

             WHERE Math < 85;

Query OK, 0 rows affected

mysql> SELECT * FROM v_ear_student;

+------+------+-----+------+---------+---------+

| s_id | name | sex | Math | Chinese | English |

+------+------+-----+------+---------+---------+

|    6 | Lucy | 女  |   84 |      85 |      89 |

+------+------+-----+------+---------+---------+

1 row in set

 

使用WITH CHECK OPTION约束时,(不指定选项则默认是CASCADED)

可以使用CASCADED或者 LOCAL选项指定检查的程度:

  ①WITH CASCADED CHECK OPTION:检查所有的视图

    例如:嵌套视图及其底层的视图

  ②WITH LOCAL CHECK OPTION:只检查将要更新的视图本身

    对嵌套视图不检查其底层的视图 

 

--五、定义视图时

CREATE [OR REPLACE]  

  [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] 

  [DEFINER = { user | CURRENT_USER }] 

  [SQL SECURITY { DEFINER | INVOKER }]

VIEW view_name [(column_list)] 

AS select_statement 

  [WITH [CASCADED | LOCAL] CHECK OPTION];

 

1、ALGORITHM选项:选择在处理定义视图的SELECT语句中使用的方法

  ①UNDEFINED:MySQL将自动选择所要使用的算法

  ②MERGE:将视图的语句与视图定义合并起来,使得视图定义的某一部分取代语句的对应部分

  ③TEMPTABLE:将视图的结果存入临时表,然后使用临时表执行语句

缺省ALGORITHM选项等同于ALGORITHM = UNDEFINED

 

2、DEFINER选项:指出谁是视图的创建者或定义者

  ①definer= '用户名'@'登陆主机'

  ②如果不指定该选项,则创建视图的用户就是定义者,指定关键字CURRENT_USER(当前用户)和不指定该选项效果相同

 

3、SQL SECURITY选项:要查询一个视图,首先必须要具有对视图的select权限。

  但是,如果同一个用户对于视图所访问的表没有SELECT权限,那会怎么样?

SQL SECURITY选项决定执行的结果:

  ①SQL SECURITY DEFINER:定义(创建)视图的用户必须对视图所访问的表具有SELECT权限,也就是说将来其他用户访问表的时候以定义者的身份,此时其他用户并没有访问权限。

  ②SQL SECURITY INVOKER:访问视图的用户必须对视图所访问的表具有SELECT权限。

缺省SQL SECURITY选项等同于SQL SECURITY DEFINER 

视图权限总结:

  使用root用户定义一个视图(推荐使用第一种):u1、u2

    1)u1作为定义者定义一个视图,u1对基表有SELECT权限,u2对视图有访问权限:u2是以定义者的身份访问可以查询到基表的内容;

    2)u1作为定义者定义一个视图,u1对基表没有SELECT权限,u2对视图有访问权限,u2对基表有SELECT权限:u2访问视图的时候是以调用者的身份,此时调用者是u2,可以查询到基表的内容。

--六、应用案例——视图的应用

1.案例的目的

  掌握视图的创建、查询、更新和删除操作

2.需求

  假如有来自江苏、山东和上海的四个理科学生报考北京大学(Peking University)和清华大学(Tsinghua University),现在需要对其考试的结果进行查询和管理,

  清华大学的录取分数线为725,北京大学的录取分数线为720.需要创建三个表对学生的信息进行管理,这三张表分别是学生表,其中这三张表的主键(Stu_id)是统一的。

3.案例操作过程

--创建数据库

mysql>CREATE DATABASE Stu_db;

Query OK, 1 row affected

--进入数据库

mysql>USE Stu_db;

Database changed

(1)创建学生表Student_tb,并插入数据。

--创建学生表Student_tb,SQL语句如下:

mysql>CREATE TABLE Student_tb(

                         Stu_id INTEGER(11) PRIMARY KEY,

                         Stu_name VARCHAR(20) NOT NULL,

                         Addr VARCHAR(50) NOT NULL,

                         Tel VARCHAR(50) NOT NULL

        );

--插入数据

mysql>INSERT INTO Student_tb(Stu_id,Stu_name,Addr,Tel) VALUES (1218022601,'赵四','上海',13889075861),

                                                                                                                                (1218022602,'张三','江苏',13953508223),

                                                                                                                                (1218022603,'李五','江苏',13953508221),

                                                                                                                                (1218022604,'王六','山东',13953508222);

--使用DESCRIBE语句查询Student_tb表结构

mysql>DESC Student_tb;                                           

+----------+-------------+------+-----+---------+-------+

| Field    | Type        | Null | Key | Default | Extra |

+----------+-------------+------+-----+---------+-------+

| Stu_id   | int(11)     | NO   | PRI | NULL    |       |

| Stu_name | varchar(20) | NO   |     | NULL    |       |

| Addr     | varchar(50) | NO   |     | NULL    |       |

| Tel      | varchar(50) | NO   |     | NULL    |       |

+----------+-------------+------+-----+---------+-------+

4 rows in set                                                                                                                          

--使用SELECT语句查询Student_tb数据信息

mysql>SELECT * FROM Student_tb;

+------------+----------+------+-------------+

| Stu_id     | Stu_name | Addr | Tel         |

+------------+----------+------+-------------+

| 1218022601 | 赵四     | 上海 | 13889075861 |

| 1218022602 | 张三     | 江苏 | 13953508223 |

| 1218022603 | 李五     | 江苏 | 13953508221 |

| 1218022604 | 王六     | 山东 | 13953508222 |

+------------+----------+------+-------------+

4 rows in set

 

(2)创建报名表Sign_tb,并插入数据。

--创建学生表Sign_tb,SQL语句如下:

mysql>CREATE TABLE Sign_tb(

                         Stu_id INTEGER(11) PRIMARY KEY,

                         Stu_name VARCHAR(20) NOT NULL,

                         Stu_school VARCHAR(50) NOT NULL,

                         Stu_sign_school VARCHAR(50) NOT NULL

        );

--插入数据

mysql>INSERT INTO Sign_tb(Stu_id,Stu_name,Stu_school,Stu_sign_school) VALUES (1218022601,'赵四','上海一中','北京大学'),

                                                                                                                                                                 (1218022602,'张三','江苏中学','清华大学'),

                                                                                                                                                                 (1218022603,'李五','江苏中学','北京大学'),

                                                                                                                                                                 (1218022604,'王六','山东一中','清华大学');

--使用DESCRIBE语句查询Sign_tb表结构

mysql>DESC Sign_tb;     

+-----------------+-------------+------+-----+---------+-------+

| Field           | Type        | Null | Key | Default | Extra |

+-----------------+-------------+------+-----+---------+-------+

| Stu_id          | int(11)     | NO   | PRI | NULL    |       |

| Stu_name        | varchar(20) | NO   |     | NULL    |       |

| Stu_school      | varchar(50) | NO   |     | NULL    |       |

| Stu_sign_school | varchar(50) | NO   |     | NULL    |       |

+-----------------+-------------+------+-----+---------+-------+

4 rows in set

--使用SELECT语句查询Sign_tb数据信息

mysql>SELECT * FROM Sign_tb;

+------------+----------+------------+-----------------+

| Stu_id     | Stu_name | Stu_school | Stu_sign_school |

+------------+----------+------------+-----------------+

| 1218022601 | 赵四     | 上海一中   | 北京大学        |

| 1218022602 | 张三     | 江苏中学   | 清华大学        |

| 1218022603 | 李五     | 江苏中学   | 北京大学        |

| 1218022604 | 王六     | 山东一中   | 清华大学        |

+------------+----------+------------+-----------------+

4 rows in set

(3)创建成绩表Grade_tb,并插入数据。

--创建成绩表Grade_tb,SQL语句如下:

mysql>CREATE TABLE Grade_tb(

                         Stu_id INTEGER(11) PRIMARY KEY,

                         Stu_name VARCHAR(20) NOT NULL,

                         Grade INTEGER(11) NOT NULL

        );

--插入数据

mysql>INSERT INTO Grade_tb(Stu_id,Stu_name,Grade) VALUES (1218022601,'赵四',730),

                                                                                                                  (1218022602,'张三',725),

                                                                                                                  (1218022603,'李五',736),

                                                                                                                  (1218022604,'王六',738);

--使用DESCRIBE语句查询Grade_tb表结构

mysql>DESC Grade_tb;  

+----------+-------------+------+-----+---------+-------+

| Field    | Type        | Null | Key | Default | Extra |

+----------+-------------+------+-----+---------+-------+

| Stu_id   | int(11)     | NO   | PRI | NULL    |       |

| Stu_name | varchar(20) | NO   |     | NULL    |       |

| Grade    | int(11)     | NO   |     | NULL    |       |

+----------+-------------+------+-----+---------+-------+

3 rows in set

mysql>SELECT * FROM Grade_tb;

+------------+----------+-------+

| Stu_id     | Stu_name | Grade |

+------------+----------+-------+

| 1218022601 | 赵四     |   730 |

| 1218022602 | 张三     |   725 |

| 1218022603 | 李五     |   736 |

| 1218022604 | 王六     |   738 |

+------------+----------+-------+

4 rows in set

(4)创建考上北京大学(Peking University)的学生视图

   视图的名称为View_PU,视图的内容包括考上北京大学的学生学号、姓名、成绩和报考学校名称4个字段,创建View_PU视图的SQL语句如下:

mysql>CREATE VIEW view_PU (学号,姓名,成绩,报考学校)

          AS

          SELECT Grade_tb.Stu_id,Grade_tb.Stu_name,Grade_tb.Grade,Sign_tb.Stu_sign_school

          FROM Grade_tb,Sign_tb

          WHERE Grade_tb.Stu_id=Sign_tb.Stu_id

          AND Grade_tb.Grade>=720

      AND Sign_tb.Stu_sign_school='北京大学';

--查看视图内容       

mysql>SELECT * FROM view_PU;

+------------+------+------+----------+

| 学号       | 姓名 | 成绩 | 报考学校 |

+------------+------+------+----------+

| 1218022601 | 赵四 |  730 | 北京大学 |

| 1218022603 | 李五 |  736 | 北京大学 |

+------------+------+------+----------+

2 rows in set

(5)创建考上清华大学(Tsing University)的学生视图

   视图的名称为View_TS,视图的内容包括考上清华大学的学生学号、姓名、成绩和报考学校名称4个字段,创建View_TS视图的SQL语句如下:

mysql>CREATE VIEW view_TS (学号,姓名,成绩,报考学校)

          AS

          SELECT Grade_tb.Stu_id,Grade_tb.Stu_name,Grade_tb.Grade,Sign_tb.Stu_sign_school

          FROM Grade_tb,Sign_tb

          WHERE Grade_tb.Stu_id=Sign_tb.Stu_id

          AND Grade_tb.Grade>=725

      AND Sign_tb.Stu_sign_school='清华大学';

--查看视图内容       

mysql>SELECT * FROM view_PU;

+------------+------+------+----------+

| 学号       | 姓名 | 成绩 | 报考学校 |

+------------+------+------+----------+

| 1218022602 | 张三 |  725 | 清华大学 |

| 1218022604 | 王六 |  738 | 清华大学 |

+------------+------+------+----------+

2 rows in set   

(6)更新视图

   张三的成绩在录入的时候录入错误,多录入了10分,接下来对张三的成绩进行修改,减去多录入的10分。

mysql>UPDATE Grade_tb SET Grade=Grade-10 WHERE Grade_tb.Stu_name='张三';

Query OK, 1 row affected

Rows matched: 1  Changed: 1  Warnings: 0

--使用查询语句查看修改后的Grade_tb表的数据

mysql>SELECT * FROM Grade_tb;

+------------+----------+-------+

| Stu_id     | Stu_name | Grade |

+------------+----------+-------+

| 1218022601 | 赵四     |   730 |

| 1218022602 | 张三     |   715 |

| 1218022603 | 李五     |   736 |

| 1218022604 | 王六     |   738 |

+------------+----------+-------+

4 rows in set

可以看到张三的成绩减去了多录入的10分,变成了715分。

--使用查询语句查看修改后的view_TS视图的数据

mysql> SELECT * FROM view_TS;

+------------+------+------+----------+

| 学号       | 姓名 | 成绩 | 报考学校 |

+------------+------+------+----------+

| 1218022604 | 王六 |  738 | 清华大学 |

+------------+------+------+----------+

1 row in set

由于清华大学的录取分数线是725,而修改后的张三的成绩变成了715,故此视图中就没有了张三的学生信息。

 

第八章 数据库的高级操作

一、数据备份与还原

        1.数据的备份

        2.数据的还原

二、管理用户

    1.uesr用户

        2.创建普通用户

        3.删除普通用户

        4.修改用户密码

三、权限管理

        1.MySQL的权限

        2.授予权限

        3.查看权限

        4.收回权限

--一、数据备份与还原

1.数据的备份

             --打开DOS命令行进入安装目录bin文件夹下(不用登录到MySQL数据库)

                  --存放路径默认在bin目录下

                 (1)备份单个数据库

                    --备份命令mysqldump格式

                    --格式:

                            mysqldump [-h主机名]  [-P端口] -u用户名 -p密码  --databases 数据库名 [表名1 表名2] > 文件名.sql                             

                    --示例:

                            mysqldump -uroot -proot --databases student_db > student_db_back.sql

                 (2)备份多个数据库

                    --格式:

                                     mysqldump [-h主机名]  [-P端口] -u用户名 -p密码 --databases 数据库名1 数据库名2 > 文件名.sql

                    --示例:

                                     mysqldump -uroot -proot --databases student_db account_db > multibackupfile.sql        

                 (3)备份所有数据库

           --格式:

                                     mysqldump [-h主机名]  [-P端口] -u用户名 -p密码 --all-databases > allbackupfile.sql

                    --示例:

                                     mysqldump -uroot -proot --all-databases > multibackupfile.sql        

 

2.数据的还原

                    --格式:

                                    mysql [-h主机名]  [-P端口] -u用户名 -p密码  databasename < backupfile.sql

                    --示例

                  mysql -uroot -proot 数据库名 < filename.sql

--二、管理用户                                

1.user用户

        --1.权限表

        MySQL是一个多用户的数据库,MYSQL的用户可以分为两大类:

        (1)超级管理员用户(root),拥有全部权限

        (2)普通用户,由root创建,普通用户只拥有root所分配的权限

 

        --2.权限表的位置

                 数据库:mysql

                 与权限相关的数据表:user,db,host,tables_priv,columns_priv,procs_priv等

        --3.user表

                 User表存储了:

                 (1)用户的信息:hosts(用户所在的主机),user(用户名),password(密码)

                 (2)用户的权限信息:_priv,主要有Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv

                 (3)安全性相关的信息:ssl_,x509,记录用户登录的验证操作等

                 (4)与资源分配相关的信息:max_,

                         max_questions表示用户在一个小时内最多可以进行的查询次数。

                         max_updates表示用户在一个小时内最多可以进行的更新次数,也包括增加数据、删除数据。

                         max_connections:表示用户最多可以建立的连接数

                        

2.创建普通用户

    (1)使用GRANT语句创建用户(常用)

                 --语法格式:

                         GRANT privileges ON database.table

                                                   TO 'username'@'localhost' [IDENTIFIED BY [PASSWORD] 'password']

                                                                            [,'username'@'localhost' [IDENTIFIED BY [PASSWORD] 'password']]      

                                  --privileges参数表示该用户具有的权限信息

                                  --database.table表示用户的权限范围表,可以在指定的数据库、表上使用自己的权限

                                  --username参数是新用户的名称,password参数是新用户的密码

        --示例:

        --使用GRANT语句创建一个新用户,用户名为user1、密码123,并授予该用户对student_db.student 表有查询权限。

mysql>GRANT SELECT ON student_db.student TO 'user1'@ 'localhost' IDENTIFIED BY '123';

--SELECT 语句验证用户是否创建成功

mysql>SELECT HOST,USER,PASSWORD FROM user WHERE USER=user1;

                                         

                                         

        (2)使用CREATE USER 语句创建用户

                 --语法格式:

                             CREATE USER 'username'@'localhost' [IDENTIFIED BY [PASSWORD] 'password']

                                                          [,'username'@'localhost' [IDENTIFIED BY [PASSWORD] 'password']]

        --示例:

        --使用CREATE USER语句创建一个新用户,用户名为user2、密码123。

mysql>CREATE USER 'user2'@'localhost'IDENTIFIED BY '123';

--SELECT 语句验证用户是否创建成功

mysql>SELECT HOST,USER,PASSWORD FROM user WHERE USER=user2;

 

 

3.删除普通用户

        (1)使用DROP USER语句删除用户

                 --语法格式:

                         DROP USER 'username'@'localhost' [,'username'@'localhost'];

        --示例:

        --使用DROP USER语句删除用户user1

mysql>DROP USER 'user1'@'localhost';

--SELECT 语句验证用户是否删除成功

mysql>SELECT host,user,password FROM user;

        (2)使用DELETE 语句删除用户

                 --语法格式:

                         DELETE FROM mysql.user WHERE Host='localhost' AND User='username';

        --示例:

        --使用DELETE语句删除用户user2

mysql>DELETE FROM mysql.user WHERE Host='localhost' AND User='user2';

 

4.修改用户密码

    (1)修改root用户密码

           ①使用mysqladmin命令修改root用户密码

            --语法格式:

               mysqladmin -u username [-h hostname] -p password new_password;

                 --示例:

                 --使用mysqladmin命令,将root用户的密码修改给mypwd

                    mysqladmin -u root -p password mypwd;

                   

           ②使用UPDATE语句修改root用户密码

                 --语法格式:

                    UPDATE mysql.user SET Password=PASSWORD('new_password')

                                          WHERE User='username' AND 'hostname';

                 --示例:

                    UPDATE mysql.user SET Password=PASSWORD('mypwd2')

                                          WHERE User='root' AND 'localhost';

                                                                    

                 ③使用SET语句修改root用户密码

                  --语法格式:

                         SET PASSWORD=PASSWORD('new_password');

                 --使用SET语句将root用户的密码修改为mypwd3

                         SET PASSWORD=PASSWORD('mypwd3');

                

        (2)root用户修改普通用户密码

                 ①使用GRANT语句修改普通用户密码

                  --语法格式:

                         GRANT USAGE ON *.* TO 'username'@'localhost'IDENTIFIED BY [PASSWORD] 'new_password';

                 ②使用UPDATE语句修改普通用户密码

                  --语法格式:

                         UPDATE mysql.user SET Password=PASSWORD(''new_password)

                                                                     WHERE User='username' AND 'hostname';

                 ③使用SET语句修改普通用户密码

                  --语法格式:

                         SET PASSWORD FOR'username'@'hostname'=PASSWORD('new_password');

        (3)普通用户修改密码

             --语法格式:

                SET PASSWORD=PASSWORD('new_password');

 

三、权限管理

1.Mysql的权限

        (1)CREATE和DROP权限,可表以创建数据库、表、索引,或者删除已有的数据库、表、索引。

        (2)INSERT、DELETE、UPDATE、SELECT权限,可以对数据表进行增删改查。

        (3)INDEX权限,可以用于创建或删除索引,适用于所有的表。

        (4)ALTER权限,可以用于修改表的结构或重命名表。

        (5)GRANT权限,允许为其他用户授权,可用于数据库和表。

        (6)FILE权限,被赋予该权限的用户能读写MySQL服务器上的任何文件。

 

2.授予权限

        --基本语法:

          GRANT privileges [(columns)][,privileges [(columns)]] ON database.table

                         TO 'username'@'hostname' [IDENTIFIED BY [PASSWORD] 'password']

                                                                            [,'username'@'localhost' [IDENTIFIED BY [PASSWORD] 'password']]...

                                                                            [WITH with_option [with_option]...]

                 示例:

                         GRANT 权限 ON 数据库.表单名称 TO 账户名@主机名 --对某个特定数据库中的表单给予授权

                         GRANT 权限 ON 数据库.* TO 账户名@主机名 --对某个特定数据库中的所有表单给予授权

                         GRANT 权限 ON *.* TO TO 账户名@主机名 --对所有数据库及表单给予授权

                         GRANT 权限1,权限2 ON 数据库.* TO 账户名@主机名 --对某个数据库中的所有表单给予多授权

                         GRANT ALL PRIVILEGES ON *.* TO账户名@主机名 --对所有数据库及表单给予全部授权(需谨慎操作)

3.查看权限

        --基本语法:

          SHOW GRANTS FOR 'username'@'hostname';

 

4.收回权限

    --基本语法:

          REVOKE privileges [(columns)][,privileges [(columns)]] ON database.table

                FROM 'username'@'hostname'

 

--忘记密码怎么办?

--方法1:启动mysql时,跳过授权表

--Linux下

[root@controller ~]# service mysqld stop

[root@controller ~]# mysqld_safe --skip-grant-table &

[root@controller ~]# mysql

mysql> SELECT USER,HOST,PASSWORD FROM mysql.user;

+----------+-----------------------+-------------------------------------------+

| user     | host                  | password                                  |

+----------+-----------------------+-------------------------------------------+

| root     | localhost             | *A4B6157319038724E3560894F7F932C8886EBFCF |

| root     | localhost.localdomain |                                           |

| root     | 127.0.0.1             |                                           |

| root     | ::1                   |                                           |

|          | localhost             |                                           |

|          | localhost.localdomain |                                           |

| root     | %                     | *23AE809DDACAF96AF0FD78ED04B6A265E05AA257 |

+----------+-----------------------+-------------------------------------------+

mysql> UPDATE mysql.user SET PASSWORD=PASSWORD("123") WHERE USER="root" AND HOST="localhost";

mysql> FLUSH privileges;

mysql> exit

[root@controller ~]# service mysqld restart

[root@controller ~]# mysql -uroot -p123

 

--方法2(删库):

--删除与权限相关的库mysql,所有的授权信息都丢失,主要用于测试数据库或者刚刚建库不久没有授权数据的情况(从删库到跑路)

[root@controller ~]# rm -rf /var/lib/mysql/mysql

[root@controller ~]# service mysqld restart

[root@controller ~]# mysql

你可能感兴趣的:(数据库基础)