第一篇 数据库MySql

数据库的简介

 数据库:存储数据的仓库python

数据库管理系统软件

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

关系型数据库:存在磁盘上linux

非关系型数据库:存在内存上正则表达式

数据库系统

数据库系统DBS(Data Base System,简称DBS)一般由软件、数据库和数据管理员组成。其软件主要包括操做系统、各类宿主语言、实用程序以及数据库管理系统。数据库由数据库管理系通通一管理,数据的插入、修改和检索均要经过数据库管理系统进行。数据管理员负责建立、监控和维护整个数据库,使数据能被任何有权使用的人有效使用。sql

                        

 

mysql

一.安装

linux版本:数据库

1. 安装
yum install mysql-server

2. 服务端启动npm

mysql.server start

3. 客户端链接windows

链接:
    mysql -h host -u user -p
 
    常见错误:
        ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2), it means that the MySQL server daemon (Unix) or service (Windows) is not running.
退出:
    QUIT 或者 Control+D

win版本:性能优化

1. 下载zip包服务器

http://dev.mysql.com/downloads/mysql/ 
2. 解压
直接解压到某个目录下,如:E:\mysql-8.0.12-winx64

三、初始化

MySQL解压后的 bin 目录下有一大堆的可执行文件,初始化针对的是服务端mysqld

执行以下命令初始化数据:

C:\Users\mamingchen>E:

E:\>cd E:\mysql-8.0.12-winx64\bin

E:\mysql-8.0.12-winx64\bin>mysqld --initialize-insecure

E:\mysql-8.0.12-winx64\bin>

初始化完成后:
1. 目录下面生成一个data文件夹
2. 建立用户名:root ,密码为空

四、启动MySQL服务

# 进入可执行文件目录
cd E:\mysql-8.0.12-winx64\bin
 
# 执行下面的命令启动MySQL服务
mysqld

就启动了服务,等待客户端去链接

五、启动MySQL客户端并链接MySQL服务

因为初始化时使用的【mysqld --initialize-insecure】命令,其默认未给root帐户设置密码

# 因此,另行开个cmd,进入可执行文件目录

cd E:\mysql
-5.7.16-winx64\bin # 链接MySQL服务器 mysql -u root -p # 提示请输入密码,直接回车,由于初始化的时候尚未设置密码
以下:

到此为止,MySQL服务端已经安装成功而且客户端已经能够链接上,之后再操做MySQL时,只须要重复上述四、5步骤便可。可是,在四、5步骤中重复的进入可执行文件目录比较繁琐,如想往后操做简便,能够作以下操做。

a. 添加环境变量

将MySQL可执行文件添加到环境变量中,从而执行执行命令便可
【右键计算机】--》【属性】--》【高级系统设置】--》【高级】--》【环境变量】--》【在第二个内容框中找到 变量名为Path 的一行,双击】 --> 【将MySQL的bin目录路径追加到变值值中,用 ; 分割】

如:
C:\Python\Python36-32\Scripts;C:\Python\Python36-32\;"C:\Users\mamingchen\AppData\Local\Microsoft\WindowsApps;C:\Program Files (x86)\Java\jre1.8.0_151\bin;C:\Program Files (x86)\Java\jre1.8.0_151\jre\bin";E:\Users\mamingchen\AppData\Local\Programs\Fiddler;"%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin";C:\Users\mamingchen\AppData\Roaming\npm;C:\Python\Python36-32\python.exe;E:\MongoDB\Server\4.0\bin;E:\mysql-8.0.12-winx64\bin;
如此一来,之后再启动服务并链接时,仅需:
# 启动MySQL服务,在终端输入
C:\Users\mamingchen>mysqld
 
# 链接MySQL服务,在终端输入:
C:\Users\mamingchen>mysql -u root -p
b. 将MySQL服务制做成windows服务

上一步解决了一些问题,但不够完全,由于在执行【mysqd】启动MySQL服务器时,当前终端会被hang住,那么作一下设置便可解决此问题:
记住:以管理员身份运行cmd
# 制做MySQL的Windows服务,在终端执行此命令:
C:\Users\mamingchen>"E:\mysql-8.0.12-winx64\bin\mysqld" --install

# 移除MySQL的Windows服务,在终端执行此命令:
C:\Users\mamingchen>"E:\mysql-8.0.12-winx64\bin\mysqld" --remove

注册成服务以后,之后再启动和关闭MySQL服务时,仅需执行以下命令:

# 启动MySQL服务
net start mysql
# 关闭MySQL服务 net stop mysql

记住:
若是是zip包,能够本身制做Windows服务;
若是是可执行文件直接点击安装的, 系统会本身给你安装Windows服务的

这里插入一个如何删除Windows服务

1. 运行
services.msc

2. 找到要删除的服务 -- 属性-- 服务名称 

3. 复制服务名称

4. 以管理员身份启动cmd

5. 执行下面的命令
sc delete 服务名称

[SC] DeleteService 成功

 二.建立用户

1. mysql

2. mysql -uroot -p

3. show databases; -- 看有哪些表

4. use mysql;  -- 进入mysql表

5. use user;

6.  -- 建立用户和密码
1create user 'mmc'@'ip地址' identified by 'mmc123'; 

--解析:
1) 'mmc':表示登录数据库的用户名
2) @'ip地址'
    ip地址有一下规则:
-- 表示这个用户只能在ip为192.168.1.1的机器上用
a.create user 'mmc'@'192.168.1.1' identified by 'mmc123'; 

-- 表示只要ip前缀为192.168.1.的均可以使用
b.create user 'mmc'@'192.168.1.%' identified by 'mmc123'; 

-- 表示只要ip前缀为 192.168的均可以使用
c.create user 'mmc'@'192.168.%.%' identified by 'mmc123'; 

-- 表示全部IP均可以使用
d.create user 'mmc'@'%' identified by 'mmc123'; 

三. 受权

1. 授予什么权限给谁
-- 将db1库下面的t1表的 查询,插入,更新的权限授予 mmc
-- 下面的意思就是mmc用户在全部机器上都能对db1库下面的t1表进行查询,插入和更新操做
grant select,insert,update on db1.t1 to 'mmc'@'%';

-- 给mmc全部权限,除了grant以外
grant all privileges on db1.t1 to 'mmc'@'%';

-- 表示mmc只能看db1库下面的全部表
grant all privileges on db1.*  to 'mmc'@'%';

四.用户管理

建立用户
    create user '用户名'@'IP地址' identified by '密码';
删除用户
    drop user '用户名'@'IP地址';
修改用户
    rename user '用户名'@'IP地址'; to '新用户名'@'IP地址';;
修改密码
    set password for '用户名'@'IP地址' = Password('新密码')
  
PS:用户权限相关数据保存在mysql数据库的user表中,因此也能够直接对其进行操做(不建议)

五.受权管理

show grants for '用户'@'IP地址'                  -- 查看权限
grant  权限 on 数据库.表 to   '用户'@'IP地址'      -- 受权
revoke 权限 on 数据库.表 from '用户'@'IP地址'      -- 取消权限
all privileges          除grant外的全部权限
select                  仅查权限
select,insert           查和插入权限
...
usage                   无访问权限
alter                   使用alter table
alter routine           使用alter procedure和drop procedure
create                  使用create table
create routine          使用create procedure
create temporary tables 使用create temporary tables
create user             使用create userdrop user、rename user和revoke  all privileges
create view             使用create view
delete                  使用delete
drop                    使用drop table
execute                 使用call和存储过程
file                    使用select into outfile 和 load data infile
grant option            使用grant 和 revoke
index                   使用index
insert                  使用insert
lock tables             使用lock table
process                 使用show full processlist
select                  使用select
show databases          使用show databases
show view               使用show view
update                  使用update
reload                  使用flush
shutdown                使用mysqladmin shutdown(关闭MySQL)
super                   􏱂􏰈使用change master、kill、logs、purge、master和set global。还容许mysqladmin􏵗􏵘􏲊􏲋调试登录
replication client      服务器位置的访问
replication slave       由复制从属使用
对于目标数据库以及内部其余:
            数据库名.*              数据库中的全部
            数据库名.表             指定数据库中的某张表
            数据库名.存储过程     指定数据库中的存储过程
            *.*                        全部数据库
用户名@IP地址         用户只能在改IP下才能访问
用户名@192.168.1.%   用户只能在改IP段下才能访问(通配符%表示任意)
用户名@%             用户能够再任意IP下访问(默认IP地址为%)
grant all privileges on db1.tb1 TO '用户名'@'IP'

grant select on db1.* TO '用户名'@'IP'

grant select,insert on *.* TO '用户名'@'IP'

revoke select on db1.tb1 from '用户名'@'IP'
示例

特殊的:

flush privileges,将数据读取到内存中,从而当即生效。
# 启动免受权服务端
mysqld --skip-grant-tables

# 客户端
mysql -u root -p

# 修改用户名密码
update mysql.user set authentication_string=password('666') where user='root';
flush privileges;

忘记密码
忘记密码

 

启动

service mysqld start  #开启
chkconfig mysqld on   #设置开机自启

OR

systemctl start mariadb
systemctl enable mariadb

查看

-- ps aux |grep mysqld    #查看进程
-- netstat -an |grep 3306 #查看端口

设置密码

-- mysqladmin -uroot password '123'   #设置初始密码,初始密码为空所以-p选项没有用
-- mysqladmin -u root -p123 password '1234' #修改root用户密码

登陆

-- mysql               #本地登陆,默认用户root,空密码,用户为root@127.0.0.1
-- mysql -uroot -p1234 #本地登陆,指定用户名和密码,用户为root@127.0.0.1
-- mysql -uroot -p1234 -h 192.168.31.95 #远程登陆,用户为root@192.168.31.95

mysql的经常使用命令

-- 
-- 启动mysql服务与中止mysql服务命令:
-- 
-- net start mysql
-- net stop  mysql
-- 
-- 
-- 登录与退出命令:
-- 
--    mysql -h 服务器IP -P 端口号 -u  用户名 -p 密码 --prompt 命令提示符  --delimiter 指定分隔符
--    mysql -h 127.0.0.1 -P 3306 -uroot -p123
--    quit------exit----\q;
-- 
-- 
-- \s;   ------my.ini文件:[mysql] default-character-set=gbk [mysqld] character-set-server=gbk
-- 
-- prompt 命令提示符(\D:当前日期 \d:当前数据库  \u:当前用户)
-- 
-- \T(开始日志) \t(结束日志)
-- 
-- show warnings;
-- 
-- help() ? \h
-- 
-- \G;
-- 
-- select now();
-- select version();
-- select user;
-- 
-- \c 取消命令
-- 
-- delimiter 指定分隔符

忘记密码怎么办?

方法1:启动mysql时,跳过受权表

[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

 

sql及其规范

sql是Structured Query Language(结构化查询语言)的缩写。SQL是专为数据库而创建的操做命令集,是一种功能齐全的数据库语言。

在使用它时,只须要发出“作什么”的命令,“怎么作”是不用使用者考虑的。SQL功能强大、简单易学、使用方便,已经成为了数据库操做的基础,而且如今几乎全部的数据库均支持sql。

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

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

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

SELECT * FROM tb_table
            WHERE NAME="YUAN";

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

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

<5>sql语句能够折行操做

<6> DDL,DML和DCL,三部分共同构成了sql语句

  DDL:定义语言;

  DML:操做语言,如:增删改查

  DCL:控制语言;如:权限控制

-- -- DML(data manipulation language):
--    它们是SELECT、UPDATE、INSERT、DELETE,就象它的名字同样,这4条命令是用来对数据库里的
--    数据进行操做的语言
-- 
-- -- DDL(data definition language):
--    DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定义或改变表(TABLE)的结构,数据类型,表之间的连接和约束等初始化工做上,
    他们大多在创建表时使用
-- -- -- DCL(Data Control Language): -- 是数据库控制功能。是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等) -- 语句。在默认状态下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人员才有权力执行DCL

 

数据库操做(DDL)

-- 1.建立数据库(在磁盘上建立一个对应的文件夹)
    create database [if not exists] db_name [character set xxx] 
    
-- 2.查看数据库
    show databases;查看全部数据库
    show create database db_name; 查看某个数据库的建立方式

-- 3.修改数据库
    alter database db_name [character set 编码格式] 

-- 4.删除数据库
    drop database [if exists] db_name;
    
-- 5.使用数据库
    切换数据库 use db_name; -- 注意:进入到某个数据库后没办法再退回以前状态,但能够经过use进行切换
    查看当前使用的数据库 select database();

-- 6. 查看错误信息
  show warnings;

mysql数据类型

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

数值类型

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

 

日期和时间类型

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

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

 

字符串类型

字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工做以及如何在查询中使用这些类型。

 

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 table_name(
            field1 type[完整性约束条件],
            field2 type,
            ...
            fieldn type
        )[character set xxx];

         -- 示例:建立一个员工表employee

         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 主键字段必须是数字类型。
       外键约束 foreign key  */

-- 2.查看表信息
    desc tab_name 查看表结构
    show columns from tab_name  查看表结构
    show tables 查看当前数据库中的全部的表
    show create table tab_name    查看当前数据库表建表语句 

-- 3.修改表结构
   -- (1)增长列(字段)
      alter table tab_name add [column] 列名 类型[完整性约束条件][first|after 字段名];
      alter table user add addr varchar(20) not null unique first/after username;
      #添加多个字段
      alter table users2 
            add addr varchar(20),
            add age  int first,
            add birth varchar(20) after name;

   -- (2)修改一列类型
      alter table tab_name modify 列名 类型 [完整性约束条件][first|after 字段名];
      alter table users2 modify age tinyint default 20;
      alter table users2 modify age int  after id;
   
   -- (3)修改列名
      alter table tab_name change [column] 列名 新列名 类型 [完整性约束条件][first|after 字段名];
      alter table users2 change age Age int default 28 first;

   -- (4)删除一列
      alter table tab_name drop [column] 列名;
      -- 思考:删除多列呢?删一个填一个呢?
      alter table users2 
            add salary float(6,2) unsigned not null after name,
            drop addr;    

   -- (5)修改表名
      rename table 表名 to 新表名;
   -- (6)修该表所用的字符集    
      alter table student character set utf8;

-- 4.删除表
    drop table tab_name;

---5 添加主键,删除主键
    alter table tab_name add primary key(字段名称,...) 
    alter table users drop primary key;

    eg:
    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
    create table test(num int primary key auto_increment);
    -- 思考,如何删除主键?
    alter table test modify id int;   -- auto_increment没了,但这样写主键依然存在,因此还要加上下面这句
    alter table test drop primary key;-- 仅仅用这句也没法直接删除主键

-- 惟一索引
    alter table tab_name add unique [index|key] [索引名称](字段名称,...) 

    alter table users add unique(name)-- 索引值默认为字段名show create table users;
    alter table users add unique key user_name(name);-- 索引值为user_name

    -- 添加联合索引
    alter table users add unique index name_age(name,age);#show create table users;

    -- 删除惟一索引
    alter table tab_name drop {index|key} index_name

建立文章表

create table article(
            id int primary key auto_increment ,
            title varchar(20),
            publish_date INT,
            click_num INT,
            is_top TINYINT(1),
            content TEXT
          );
示例

完整性约束条件之主键约束

单字段主键

主键字段特色:非空(not null)且惟一(unique)

 create table users(
            id INT primary key,
            name varchar(20),
            city varchar(20)
          );

多字段联合主键

 create table users2(
            id INT,
            name varchar(20),
            city varchar(20),
            primary key(name,id)
          );

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

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

表纪录操做(具体表里数据的操做)

表纪录之增,删,改

-- 1.增长一条记录insert

      /*insert [into] tab_name (field1,filed2,.......) values (value1,value2,.......);*/


      create table employee_new(
                 id int primary key auto_increment,
                 name varchar(20) not null unique,
                 birthday varchar(20),
                 salary float(7,2)
                             );

       insert into employee_new (id,name,birthday,salary) values
                     (1,'yuan','1990-09-09',9000);

    -- 不写字段,按找字段一一对应插入
insert into employee_new values (2,'alex','1989-08-08',3000);
    
    -- 按照字段插入
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] tab_name set 字段名=值
insert into employee_new set id=12,name="alvin3"; -- 2.修改表记录 update tab_name set field1=value1,field2=value2,......[where 语句] /* UPDATE语法能够用新值更新原有表行中的各列。 SET子句指示要修改哪些列和要给予哪些值。 WHERE子句指定应更新哪些行。如没有WHERE子句,则更新全部的行。*/ update employee_new set birthday="1989-10-24" WHERE id=1; --- 将yuan的薪水在原有基础上增长1000元。 update employee_new set salary=salary+4000 where name='yuan'; -- 3.删除表纪录 delete from tab_name [where ....] /* 若是不跟where语句则删除整张表中的数据 1) delete只能用来删除一行记录 2) delete语句只能删除表中的内容,不能删除表自己,想要删除表,用drop 3) TRUNCATE TABLE也能够删除表中的全部数据,此语句首先摧毁表,再从新建立要给同名的新表。此种方式删除的数据不能在事务中恢复。
          truncate 使用场景:好比某表有几万条数据,delete删除太慢,就用truncate,直接把这张表先删掉,而后再从新建立个同名表。
*/ -- 删除表中名称为’alex’的记录。 delete from employee_new where name='alex'; -- 删除表中全部记录。 delete from employee_new;-- 注意auto_increment没有被重置:alter table employee auto_increment=1; -- 使用truncate删除表中记录。 truncate table emp_new;

思考:

    <1>  存储时间用varchar可不能够呢?它与date数据类型又有什么区别呢?

   -- 能够的(若是只是用来显示,不对时间进行操做的时候就能够用varchar)

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

 

表纪录之查(单表查询)

-- 查询表达式

   SELECT *|field1,filed2 ...   FROM tab_name
                  WHERE 条件
                  GROUP BY field
                  HAVING 筛选
                  ORDER BY field
                  LIMIT 限制条数


 ---准备表

   CREATE TABLE ExamResult(

   id INT PRIMARY KEY  auto_increment,
   name VARCHAR (20),
   JS DOUBLE ,
   Django DOUBLE ,
   OpenStack DOUBLE
);


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);


-- (1)select [distinct] *|field1,field2,......   from tab_name
            -- 其中from指定从哪张表筛选,*表示查找全部列,也能够指定一个列
            -- 代表确指定要查找的列,distinct用来剔除重复行。

                    -- 查询表中全部学生的信息。
                    select * from ExamResult;
                    -- 查询表中全部学生的姓名和对应的英语成绩。
                    select name,JS from ExamResult;
                    -- 过滤表中重复数据。distinct后面跟要去重的字段
                    select distinct JS ,name from ExamResult;



-- (2)select 也可使用表达式,而且可使用: 字段 as 别名或者:字段 别名

                -- 在全部学生分数上加10分特长分显示。

                select name,JS+10,Django+10,OpenStack+10 from ExamResult;  -- 仅仅是当次显示的时候加了分数,数据库里可没存上哦。
-- 统计每一个学生的总分。 select name,JS+Django+OpenStack from ExamResult; -- 使用别名表示学生总分。 select name as 姓名,JS+Django+OpenStack as 总成绩 from ExamResult; select name,JS+Django+OpenStack 总成绩 from ExamResult; -- as 能够去掉,可是要取别名,推荐加上 select name JS from ExamResult; -- what will happen?---->记得加逗号 -- (3)使用where子句,进行过滤查询。 -- 查询姓名为XXX的学生成绩 select * from ExamResult where name='yuan'; -- 查询英语成绩大于90分的同窗 select id,name,JS from ExamResult where JS>90; -- 查询总分大于200分的全部同窗 select name,JS+Django+OpenStack as 总成绩 from ExamResult where JS+Django+OpenStack>200 ; -- where字句中可使用: -- 比较运算符: > < >= <= <> != (<> 和 != 都表示不等于,推荐用 !=) between 80 and 100 值在10到20之间 in(80,90,100) 值是10或20或30 like 'yuan%' /* pattern能够是%或者_, 若是是%则表示任意多字符,此例如唐僧,唐国强 若是是_则表示一个字符唐_,只有唐僧符合。两个_则表示两个字符:__ */ -- 逻辑运算符 在多个条件直接可使用逻辑运算符 and or not -- 练习 -- 查询JS分数在 70-100之间的同窗。 select name ,JS from ExamResult where JS between 80 and 100; -- 查询Django分数为75,76,77的同窗。 select name ,Django from ExamResult where Django in (75,98,77); -- 查询全部姓王的学生成绩。 select * from ExamResult where name like '王%'; -- 查询JS分>90,Django分>90的同窗。 select id,name from ExamResult where JS>90 and Django >90; -- 查找缺考数学的学生的姓名 select name from ExamResult where Database is null; -- (4)Order by 指定排序的列,排序的列便可是表中的列名,也能够是select 语句后指定的别名。 -- select *|field1,field2... from tab_name order by field [Asc|Desc] -- Asc 升序、Desc 降序,其中asc为默认值 ORDER BY 子句应位于SELECT语句的结尾。 -- 练习: -- 对JS成绩排序后输出。 select * from ExamResult order by JS; -- 对总分排序按从高到低的顺序输出 select name ,(ifnull(JS,0)+ifnull(Django,0)+ifnull(Database,0)) 总成绩 from ExamResult order by 总成绩 desc;
        select name, JS+Django+Database as 总成绩 from examresult order by 总成绩 desc; -- 按总成绩从高到低排序
-- 对姓李的学生成绩排序输出
        -- ifnull(参数一,0):表示若是参数一的字段值为null,就转换成0
select name ,(ifnull(JS,0)+ifnull(Django,0)+ifnull(OpenStack,0)) 总成绩 from ExamResult where name like 'a%' order by 总成绩 desc; -- (5)group by 分组查询--用的最多,最重要,也是最很差理解的一个:

CREATE TABLE order_menu( id INT PRIMARY KEY auto_increment, product_name VARCHAR (20), price FLOAT(6,2), born_date DATE, class VARCHAR (20) ); 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,"水果"); -- 注意,按分组条件分组后每一组只会显示第一条记录 -- group by字句,其后能够接多个列名,也能够跟having子句,对group by 的结果进行筛选。 -- 按位置字段筛选 select * from order_menu group by 5; -- 按照第5个字段分组 -- 练习:对购物表按类名分组后显示每一组商品的价格总和 select class,SUM(price)from order_menu group by class; -- 练习:对购物表按类名分组后显示每一组商品价格总和超过150的商品 select class,SUM(price)from order_menu group by class HAVING SUM(price)>150; /* having 和 where二者均可以对查询结果进行进一步的过滤,差异有: <1>where语句只能用在分组以前的筛选,having能够用在分组以后的筛选; <2>使用where语句的地方均可以用having进行替换 <3>having中能够用聚合函数,where中就不行。 */ -- GROUP_CONCAT() 函数 SELECT id,GROUP_CONCAT(name),GROUP_CONCAT(JS) from ExamResult GROUP BY id; -- (6)聚合函数: 先不要管聚合函数要干吗,先把要求的内容查出来再包上聚合函数便可。 -- (通常和分组查询配合使用) --<1> 统计表中全部记录 -- COUNT(列名):统计行的个数 -- 统计一个班级共有多少学生?先查出全部的学生,再用count包上 select count(*) from ExamResult; -- 统计JS成绩大于70的学生有多少个? select count(JS) from ExamResult where JS>70; -- 统计总分大于280的人数有多少? select count(name) from ExamResult where (ifnull(JS,0)+ifnull(Django,0)+ifnull(OpenStack,0))>280; -- 注意:count(*)统计全部行; count(字段)不统计null值. -- SUM(列名):统计知足条件的行的内容和 -- 统计一个班级JS总成绩?先查出全部的JS成绩,再用sum包上 select JS as JS总成绩 from ExamResult; select sum(JS) as JS总成绩 from ExamResult; -- 统计一个班级各科分别的总成绩 select sum(JS) as JS总成绩, sum(Django) as Django总成绩, sum(OpenStack) as OpenStack from ExamResult; -- 统计一个班级各科的成绩总和 select sum(ifnull(JS,0)+ifnull(Django,0)+ifnull(Database,0)) as 总成绩 from ExamResult; -- 统计一个班级JS成绩平均分 select sum(JS)/count(*) from ExamResult ; -- 注意:sum仅对数值起做用,不然会报错。 -- AVG(列名): -- 求一个班级JS平均分?先查出全部的JS分,而后用avg包上。 select avg(ifnull(JS,0)) from ExamResult; -- 求一个班级总分平均分 select avg((ifnull(JS,0)+ifnull(Django,0)+ifnull(Database,0))) from ExamResult ; -- Max、Min -- 求班级最高分和最低分(数值范围在统计中特别有用) select Max((ifnull(JS,0)+ifnull(Django,0)+ifnull(OpenStack,0))) 最高分 from ExamResult; select Min((ifnull(JS,0)+ifnull(Django,0)+ifnull(OpenStack,0))) 最低分 from ExamResult; -- 求购物表中单价最高的商品名称及价格 ---SELECT id, MAX(price) FROM order_menu;--id和最高价商品是一个商品吗? SELECT MAX(price) FROM order_menu; -- 注意:null 和全部的数计算都是null,因此须要用ifnull将null转换为0! -- -----ifnull(JS,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 SELECT * from ExamResult limit 1; -- 只显示查到的前3条数据 SELECT * from ExamResult limit 2,5;--跳过前两条显示接下来的五条纪录 SELECT * from ExamResult limit 2,2; --- (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}'; -- 有2个m的名字

外键约束

建立外键

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

----主表

CREATE TABLE ClassCharger(

       id TINYINT PRIMARY KEY auto_increment,
       name VARCHAR (20),
       age INT ,
       is_marriged boolean  -- show create table ClassCharger: tinyint(1)

);

INSERT INTO ClassCharger (name,age,is_marriged) VALUES ("冰冰",12,0),
                                                       ("丹丹",14,0),
                                                       ("歪歪",22,0),
                                                       ("姗姗",20,0),
                                                       ("小雨",21,0);


----子表: 有foreign key的就是字表

CREATE TABLE Student(

       id INT PRIMARY KEY auto_increment,
       name VARCHAR (20),
       charger_id TINYINT,     --切记:做为外键必定要和关联主键的数据类型保持一致
       -- [ADD CONSTRAINT charger_fk_stu]FOREIGN KEY (charger_id) REFERENCES ClassCharger(id)

) ENGINE=INNODB;
--
charger_fk_stu 外键名字
 
示例:关联外键
create table student2(
id int primary key auto_increment,
name varchar (20),
charger_id tinyint,
  -- student2表里的charger_id 字段的外键是classcharger表里的id字段
  -- 要对student2表里charger_id字段绑定外键,于 classcharger 表里的id字段相关联
foreign key (charger_id) references classcharger(id)
)ENGINE=INNODB;

INSERT INTO Student(name,charger_id) VALUES ("alvin1",2), ("alvin2",4), ("alvin3",1), ("alvin4",3), ("alvin5",1), ("alvin6",3), ("alvin7",2); DELETE FROM ClassCharger WHERE name="冰冰"; INSERT student (name,charger_id) VALUES ("yuan",1); -- 删除竟然成功,但是 alvin3显示仍是有班主任id=1的冰冰的; -----------增长外键和删除外键--------- ALTER TABLE student ADD CONSTRAINT abc -- 给外键起个名字叫 abc FOREIGN KEY(charger_id) -- 指定哪一个字段做为外键 REFERENCES classcharger(id); -- 关联到哪张表的哪一个字段 -- 删除外键 ALTER TABLE student DROP FOREIGN KEY abc;

 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 --级联删除 示例:
create table student3(
id int primary key auto_increment,
name varchar (20),
charger_id tinyint,
foreign key (charger_id) references classcharger(id) on delete cascade
) ENGINE = INNODB;
------set null方式: 在父表上update/delete记录时,将子表上匹配记录的列设为null;

------要注意子表的外键列不能为not null
FOREIGN KEY (charger_id) REFERENCES ClassCharger(id) ON DELETE SET NULL

示例:
能够将student3里的外键删除,而后改为set null
-- 先删除外键
alter table
student3 drop froeign key 外键名字;
-- 将外键改成set null
alter table student3 add constraint s3_fk_ss foreign key (charger_id) references classcharger (id) on delete set null;
------Restrict方式 :拒绝对父表进行删除更新操做(了解)

------No action方式 在mysql中同Restrict,若是子表中有匹配的记录,则不容许对父表对应候选键
   -- 进行update/delete操做(了解)

 

多表查询

准备表

-- 准备两张表
-- company.employee
-- company.department

      create table employee(
      emp_id int auto_increment primary key not null,
      emp_name varchar(50),
      age int,
      dept_id int
      );

      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);


    create table department(
       dept_id int,
       dept_name varchar(100)
      );

    insert into department values
      (200,'人事部'),
      (201,'技术部'),
      (202,'销售部'),
      (203,'财政部');

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 |
+--------+----------+------+---------+
rows in set (0.00 sec)

mysql> select * from department;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|     200 | 人事部    |
|     201 | 技术部    |
|     202 | 销售部    |
|     203 | 财政部    |
+---------+-----------+
rows in set (0.01 sec)

多表查询之链接查询

1.笛卡尔积查询

mysql> SELECT * FROM employee,department;

--        select employee.emp_id,employee.emp_name,employee.age,
--        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 | 财政部    |
+--------+----------+------+---------+---------+-----------+

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


  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 | 人事部    |
      +--------+----------+------+---------+---------+-----------+
 示例:筛选出A所在的部门 select employee.emp_name,department.dept_name from employee,department where employee.dept_id = department.dept_id and employee.emp_name = "A"; 
select employee.emp_name,department.dept_name from department inner join employee on employee.dept_id = department.dept_id and employee.emp_name = "A";

3.外链接

--(1)左外链接:在内链接的基础上增长左边有右边没有的结果  -- 用的多
左链接以左边的employee表为主,employee表的所有字段都显示,没有匹配上的就显示空null
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 | 销售部 | | 6 | F | 38 | 204 | NULL | NULL | +--------+----------+------+---------+---------+-----------+ --(2)右外链接:在内链接的基础上增长右边有左边没有的结果 右外链接以右边的department表为主,department表的所有字段都显示 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 | 人事部 | | 2 | B | 26 | 201 | 201 | 技术部 | | 3 | C | 30 | 201 | 201 | 技术部 | | 4 | D | 24 | 202 | 202 | 销售部 | | 5 | E | 20 | 200 | 200 | 人事部 | | NULL | NULL | NULL | NULL | 203 | 财政部 | +--------+----------+------+---------+---------+-----------+ --(3)全外链接:在内链接的基础上增长左边有右边没有的和右边有左边没有的结果 -- mysql不支持全外链接 full JOIN -- mysql可使用Union方式间接实现全外链接 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 | 人事部 | | 2 | B | 26 | 201 | 201 | 技术部 | | 3 | C | 30 | 201 | 201 | 技术部 | | 4 | D | 24 | 202 | 202 | 销售部 | | 5 | E | 20 | 200 | 200 | 人事部 | | NULL | NULL | NULL | NULL | 203 | 财政部 | | 6 | F | 38 | 204 | NULL | NULL | +--------+----------+------+---------+---------+-----------+ -- 注意 union与union all的区别:union会去掉相同的纪录

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

-- 找出年龄大于等于25岁的员工所在的部门
-- 筛选出的是技术部,须要去重,加个 distinct 去重
SELECT DISTINCT department.dept_name FROM employee,department WHERE employee.dept_id = department.dept_id AND age>25; --之内链接的方式查询employee和department表,而且以age字段的升序方式显示 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;

多表查询之子查询

-- 子查询是将一个查询语句嵌套在另外一个查询语句中。
-- 内层查询语句的查询结果,能够为外层查询语句提供查询条件。
-- 子查询中能够包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
-- 还能够包含比较运算符:= 、 !=、> 、<等


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

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

   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 |
+--------+----------+------+---------+
rows in set (0.01 sec)



-- 2. 带比较运算符的子查询
      --      =、!=、>、>=、<、<=、<>

     -- 查询员工年龄大于等于25岁的部门
     select dept_id,dept_name from department
           where dept_id IN
          (select DISTINCT dept_id from employee where age>=25);

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

-- EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。
-- 而是返回一个真假值。Ture或False
-- 当返回Ture时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询

     select * from employee
              WHERE EXISTS
              (SELECT dept_name from department where dept_id=203);

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


     select * from employee
                WHERE EXISTS
              (SELECT dept_name from department where dept_id=205);

     -- Empty set (0.00 sec)


    ps:  create table t1(select * from t2);

索引

索引简介

索引在MySql中也叫作“键”,是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能很是关键,尤为是当表中的数据量愈来愈大时,索引对于性能

的影响愈发重要。

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

索引可以轻易将查询性能提升好几个数量级。

索引至关于字典的音序表,若是要查某个字,若是不使用音序表,则须要从几百页中逐页去查。(或者理解为目录)

索引的特色:

  建立与维护索引会消耗不少时间与磁盘空间,但查询速度大大提升。

索引语法

-- 建立表时
-- 语法

create table 表名(
      字段名1  数据类型 [完整性约束条件],
      字段名2  数据类型 [完整性约束条件],
      字段名3  数据类型 [完整性约束条件],
      [unique | FULLTEXT | SPATIAL] INDEX | KEY [索引名](字段名[长度]) [asc | desc ]
      
);

-- [unique | FULLTEXT | SPATIAL]: 可加可不加的
-- unique:惟一索引;不能重复
-- FULLTEXT:全局索引;
-- SPATIAL:空间索引
-- 若是不加上面三个,直接用index 或者 key: 建立普通索引
-- index 或者 key 后面跟的是索引名字 
-- 索引名可写可不写,不写的话,默认就与字段名同样

-- 建立普通索引示例:
create table test1(
  id int primary key auto_increment,
  name varchar (20),
  index index_name (name )   -- 建立普通索引 能够用 index,也能够用key, 两个是彻底同样的,index_name可写可不写
  sarlay int default 1000
);

-- 建立惟一索引

-- 对已经存在的表添加个惟一索引示例:
alter table test1 modify name varchar (20) unique ;

-- 建立惟一索引示例
create table emp2(
  id int,
  name varchar (20),
  bank_num char (19) unique ,
  resume varchar (50),
  unique index index_emp_name(name )
);


-- 建立全文索引示例
create table emp3(
  id int,
  name varchar (20),
  resume varchar (500),
  FULLTEXT index index_resume (resume )
)

--建立多列索引示例:
create table emp4(
  id int,
  name varchar (20),
  resume varchar (500),
  Index index_name_resume (name,resume ) -- 给 name 和 resume 两列都共用一个索引
)

添加索引(在已经建立好表的状况下,添加索引)

-- create在已经存在的表上建立索引
create [unique | FULLTEXT | SPATIAL] index 索引名
  on 表名 (字段名[(长度)] [asc | desc ]);  -- on 表示给哪张表下的哪一个字段添加索引
  
-- alter table 在已经存在的表上建立索引
-- alter是先把表找到,而后再给该表下的哪一个字段添加索引
alter table 表名 add [unique | FULLTEXT | SPATIAL] index 
  索引名 (字段名[(长度)] [asc | desc ]);

删除索引

  -- 语法
  drop index 索引名 on 表名;
  
  -- 示例
  drop index index_name on t2;

索引测试实验

-- 建立表
create table Indexdb.t1(id int ,name varchar (40));

-- 存储过程
-- 经过循环,插入50条数据

delimiter ! -- 修改结束符的,好比上面一个sql语句结束,都是以;结尾,能够修改成!
create procedure autoinsert()   -- procedure:是个关键字,表示存储过程,autoinsert() 是定义的函数名字
begin
declare i int default 1;  -- 声明一个变量i,从1开始
while (i <500000) do
insert into Indexdb.t1 values (i,"yuan");
set i = i+1;
end while;
end !

delimiter ;  -- 分隔符再改会来

-- 调用函数插入50万条数据
call autoinsert();

-- 花费时间比较
-- 建立索引前
select * from Indexdb.t1 where id=300000; -- 0.32s

-- 添加索引
alter table Indexdb.t1 add index index_id (id);

-- 添加索引后
select * from Indexdb.t1 where id=300000; -- 0.01s
相关文章
相关标签/搜索