mysql学习笔记

  • net start /stop/ mysql    [注意在wamp下mysql的进程名叫wampmysqld]

MySQL 5 权威指南 第三版 Michael Kofler

http://www.apress.com/cn/book/9781590595350 源码下载

注,书籍比较老,可能一些知识点过时了。新版的MySQL功能也可能改进或改变了。

MySQL5.7的官方文档(这是最权威的学习地方,英文也不难):https://dev.mysql.com/doc/refman/5.7/en/

https://www.cnblogs.com/lyhabc/p/3776739.html 【一篇好的博客】

目录

0,前言 

1,入门

  • 第1章
  • 第2章
  • 第3章

2,管理工具和用户操作界面

  • 第4章
  • 第5章
  • 第6章
  • 第7章

3,基础知识

  • 第8章
  • 第9章
  • 第10章
  • 第11章
  • 第12章
  • 第13章
  • 第14章

4,程序设计

  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

5,参考资料

  • 第21章:SQL语法指南
    • SQL命令指南(按字母顺序)
    • SQL函数指南
  • 第22章
  • 第23章

6,附录

windows下停止和启动MySQL(貌似不支持重启)

net stop mysql;(如果用的是集成环境wamp,则net stop wampmysqld).

net start mysql;同上

Linux(Ubuntu)下MySQL的停止,启动和重启:

sudo service mysql stop;

sudo service mysql start;

sudo service mysql restart;

 


 显示和设置系统变量:global表示是全局值,session表示当前会话的值

※显示系统变量:

①show variables like "%updatable_views_with_limit%";//这是MySQL服务器的当前会话的值,第一次进来时则使用的是服务器的全局值。

②select @@global.updatable_views_with_limit;//这是MySQL服务器的全局值

显示当前会话的值

  • select @@session.updatable_views_with_limit;

④select @@updatable_views_with_limit; //如果session中有此变量,则显示session的值,否则显示global的值

 

※设置系统变量

设置全局变量(要求SUPER权限),该值将会被记住,此后所有新建的的MySQL连接(注意是连接,MySQL服务器还是同一次)都将使用该值(当前连接不包括在内),该值的效力直到服务器重启为止。如果想永久改变变量值,应该把此变量值写入配置文件中,这样每次服务器重启都会读取这个值

  • set @@global.foreign_key_checks=1
  • set global foreign_key_checks=1 

设置当前会话(session)的值,该值的效力 直到当前会话结束或者被设置为另外一个值为止

  • set @@session.foreign_key_checks=1
  • set session foreign_key_checks = 1

优先设置会话值,如果会话中没有此变量,则设置全局变量

  • set @@foreign_key_checks=1 
  • set foreign_key_checks=1 

如果在同一个语句中设置了多个系统变量,则最后一个global或session选项被用于没有指定模式的变量。

如果想把一个session变量设置为global值或者反过来,可以使用关键词DEFAULT,以下两个语句效果一样:

  • SET max_join_size = DEFAULT;
  • SET @@session.max_join_size = @@global.max_join_size;

※SET PASSWORD命令

SET命令也可以用来改变连接密码。但是PASSWORD本身可不是一个变量!

  • SET PASSWORD = PASSWORD('xxx');
  • SET PASSWORD FOR user@hostname = PASSWORD('xxx');

新版的MySQL显示直接使用     SET PASSWORD = 'xxx'     即可。


将mysql的输出结果输出到外部文件  (SQL结果与文件的关联可以全文搜索关键词 infile 和 outfile)

方法一:
直接执行命令:
mysql> select count(1) from table  into outfile '/tmp/test.xls'; //注意windows下的路径要用/而不是\

Query OK, 31 rows affected (0.00 sec)
在目录/tmp/下会产生文件test.xls
遇到的问题:
mysql> select count(1) from table   into outfile '/data/test.xls';
报错:
ERROR 1 (HY000): Can't create/write to file '/data/test.xls' (Errcode: 13)
可能原因:mysql没有向/data/下写的权限 
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
解决方法:修改MySQL配置文件/etc/mysql/my.cnf,在[mysqld]模块下添加一句secure_file_priv="/"即可。
方法二:
查询都自动写入文件:
mysql> pager cat > /tmp/test.txt ;
PAGER set to 'cat > /tmp/test.txt'
之后的所有查询结果都自动写入/tmp/test.txt',并前后覆盖
mysql> select * from table ;
30 rows in set (0.59 sec)
在框口不再显示查询结果
方法三:
跳出mysql命令行
[root@SHNHDX63-146 ~]# mysql -h 127.0.0.1 -u root -p XXXX -P 3306 -e "select * from table"  > /tmp/test/txt

向mysql.user数据表中插入一个用户
向此数据表中插入一个用户可以新建一个mysql用户,注意要重启MySQL服务器之后这个用户才生效。同样,从user中删除一个用户也要重启才生效。
insert into mysql.user(host,user, ssl_cipher, x509_issuer, x509_subject, authentication_string ) values ('localhost', 'shan', '', '', '', password('shan'));

11
22

0.1,一些缩略语

GPL:GNU Public License(GNU 公共许可证),开源软件普遍采用的一种软件许可证制度。以GPL软件为基础开发出来的每一个程序都必须沿用GPL许可证(换句话说,GPL许可证的约束力是可以传递的)。如果打算在一个GPL程序的基础上开发一个商业化产品,就必须公开并允许别人 在开源的意义下自由使用改写的那部分代码。绝大数商业化软件的开发者是不愿意这么做的。

InnoDB:InnoDB是一家公司的名字,该公司为MySQL数据库开发了一种特殊的数据表格式,该格式的名字也叫InnoDB。

ODBC:Open DataBase Connectivity(开放数据库互连标准),它是一组为了让不同厂商推出的数据库产品能够互相兼容而制定的标准化数据库访问接口。

PHP:PHP Hypertext Preprocessor(PHP超文本预处理器),一种用来生成和处理HTML页面的脚本程序设计语言

 


 

一,入门

1,什么是MySQL

1.1,数据表之间有种种内在的交叉引用关系,存在于数据表之间的这种关系使数据库又被称为关系型数据库(另外还有市场占有份额相当少的 面向对象数据库系统)。

1.2,查询结果也是一个数据表,只不过这个数据表只存在于计算机的内存(RAM)里而不是在硬盘上【数据库中的数据实际都是通过硬盘上的文件存储的,】.

1.3, 索引(index)是一种辅助性的数据表,它们只包含一种信息:原始数据记录的排序情况。索引也被称为键(key)。索引有助于加快对数据的访问速度,但也有一些弊端:①索引会增加数据库文件在硬盘上的控件占用量。②索引必须随原始数据同步更新才有实际意义,换句话说,在读取数据时,索引可以节省时间;但是在输入和修改数据时,索引反而会“浪费”时间。从全局观点看,索引是提高了效率还是降低了效率将取决于用户选用了哪一项数据作为索引。

1.4,MySQL的功能

1.4.1,客户/服务器体系。MySQL整个系统由一个数据库服务器(即MySQL本身)和任意多个客户(应用程序,比如PHP的MySQL模块,再比如mysql.exe程序)构成。客户通过与服务器进行通信的方式来完成数据的查询和保存修改等操作。客户既可以与服务器运行在同一台计算机上,也可以运行在另外一台计算机上(此时,将通过一个本地网络或因特网进行通信)。

   常见的大型数据库系统(Oracle,Microsoft SQL Server等)几乎都是客户/服务器系统。与它们形成对照的是  文件服务器系统(file-server system),文件服务器系统的最大缺陷是 在网络上运行时会因为用户人数的的增加而变得非常缺乏效率。

1.4.2,show variables like "version";//查看MySQL软件的版本号。

 


 

2,在window系统上安装MySQL和相关软件(apache,php,perl等)安装   (windows 和 linux系统下,需要时再研究)。

 


 

3,MySQL + PHP初级案例研究

3.1,MySQL和mysql之间的区别很多人都不清楚:(其实就是客户/服务器体系的关系)

MySQL说的是数据库服务器,它通常会在系统开机时自动启动并在后台保持运行。这个服务器程序的名字在UNIX/Linux环境下叫做mysqld,在windows环境下叫做mysqld.exe或mysqld-nt.ext。

mysql和mysql.exe则是命令行解释器,属于软件工具(属于客户端程序),用于人们以交互方式MySQL数据库系统进行维护或管理。mysql程序的任务是把人们以交互方式发出的命令传递给MySQL服务器,再把那些命令的执行结果显示在屏幕上。mysql程序的替代品包括MySQL Administrator和简便易用的HTML操作界面phpMyAdmin.

3.2, status命令可以显示许多数据库的状态信息。

 

二,管理工具和用户操作界面

目录:

第一章: mysql、mysqladmin和mysqldump

第二章:MySQL Administrator和MySQL Query Browser

第三章:phpMyAdmin

第四章:Microsoft Office 和 openOffice/StarOffice

1,mysql、mysqladmin和mysqldump

1.1,MySQL是一种客户/服务器体系的数据库系统,它的服务器部分在启动运行后没有人机页面,所以终端用户无法直接使用MySQL,只能通过各种MySQL客户程序或Web站点访问数据库、录入新数据和备份数据。

客户端程序包括mysql,mysqladmin和mysqldump(既是命令也是程序)等。web站点包括MySQL Administrator、MySQL Query Browser 和 phpMyAdmin等工具。

 


 

1.2,mysql的用法

1.2.1,mysql启动选项介绍:

※-u name 或 --user=name

※-p 或--password=[你的密码],如果密码为空则--password= (注意这里空一格即可,不可写作"")

※-h 或 --host=computername

※--protocal=name:这个选项用来给出打算使用的通信协议。这个选项一般不需给出,由mysql程序自行选用的通信协议往往就是正确的。

mysql学习笔记_第1张图片

※-P n 或 --port=n:指定端口号。MySQL服务器默认通信端口是3306.这个选项只有在mysql程序和MySQL服务器使用Tcp/Ip协议进行通信的时候才有意义。

※--default-charater-set=name:这个选项给出mysql程序和MySQL服务器进行通信时使用的字符集。这个字符集应该与 输入窗口(windows)或控制台窗口(UNIX/Linux)里默认使用的字符集保持一致。MySQL支持的字符集有以下几种:latin1(ISO-8559-1)、latin2(ISO-8559-2)、utf8(Unicode)和cp850(西欧使用的DOS字符集)。

※--database=xxx:指定将要使用的数据库。经测试这个参数也可以不用键,直接写数据库的名字(直接写的之所以会被当作数据库名而不是其他是因为 其他的任何 参数都必须带着键);

一个示例:mysql -h localhost --user=root --password= test_database//直接进入test_database数据库

※--i-am-a-dummy:新手保护机制。这个只有键没有值。如果发出的update和delete命令里没有关键字where或limit,mysql程序就会拒绝执行。

※-E:使用此选项后,查询结果将默认以列的方式显示(即将数据表的结构旋转90度)。如果不使用此参数,也可是让MySQL以列的方式显示,方法是将查询语句最后的分号变为\G(不再需要分号,并且注意是个大写的G。另外MySQL中小写的 \g 和 分号 是等价的)。

 

1.2.2,交互式使用mysql(即进入mysql后,输入SQL命令等等)

一些常用的mysql命令及简写形式见下表:

mysql学习笔记_第2张图片

1.2.2.1,UNIX/Linux环境中mysql的使用技巧

0,Linux下全局配置文件位置一般在/etc/mysql/my.cnf

①,个人配置文件(windows下没有个人配置文件,只有一个全局配置文件my.ini)。在UNIX/Linux环境下,可以把自己常用的设置参数和选项保存到一个名为~/.my.cnf的用户级配置文件里去。具体的说,把使用于所有客户工具(如mysql,mysqldump,mysqladmin等)的选项集中安排在[client]部分里,把只适用于mysql程序的选项集中安排在[mysql]部分里。如下例子所示:

#Options for all MySQL tools

[client]

user=username

password=xxx

#Options for mysql

[mysql]

database=mydatabase

 因为这个文件有明文密码,所以不应让别人看到:chmod 600 ~/.my.cnf

②字符集问题

如果mysql程序和MySQL服务器使用的字符集不是同一种,就会 造成某些不常用的特殊字符无法正确显示。这类方法有两种方法:

□,启动mysql程序后,立即执行SQL命令 SET NAMES 'name',命令中的name是字符集编码。这个使用SQL 命令解决,所以对php等也是适用的。

□,另一种解决方法是在启动时增加--defalut-character-set=name选项,name是字符集编码。

 在mysql程序里执行status(或\s)命令:字符集信息出现在Server和Conn.character set行上。

 

1.2.2.2,Windows环境下mysql的使用技巧

①,字符集问题

除了上述UNIX/Linux下的解决方法之外,windows下还可以在DOS窗口所使用的字体和字符集上动脑筋。如果MySQL服务器使用的默认字符集是latin1,可以在DOS窗口里输入CHCP 1252命令以启动Codepage 1252(Codepage 是windows对字符集的称呼。Codepage 1252大致对应于Latin1字符集)。如果MySQL服务器使用的默认字符集是utf8,则可以执行CHCP 65001命令(Codepage 65001对应于Unicode字符集utf8).

 

1.2.3,用mysql处理SQL文件

mysql程序除了以交互方式执行SQL命令,还可以处理存在文件里的SQL命令。只须如下所示启动mysql程序即可(注意,这里是尚未进入mysql中 的命令):

mysql [options] databasename < filename

其中的options和启动mysql时的选项一样(-u,-p等)

 


1.3,mysqladmin的用法

mysqladmin程序有助于完成许多系统管理任务,如创建或删除一个数据库、修改密码等。它的语法命令很简单:

mysqladmin [options] admincommand

其中的[options]和mysql启动选项一样。admincommand是mysqladmin将要执行的任务。这里只介绍3个最重要的命令:创建数据库(create),删除数据库(drop),改变数据库的密码(password).

> mysqladmin -uroot -p create newdatabase

password: *********

> mysqladmin -uroot -p drop testdatabase

password: *********

 

Dropping the database is potentially a very bad thing to do.
Any data stored in the database will be destroyed.

 

Do you really want to drop the 'test' database [y/N] y
Database "test" dropped

> mysqladmin -uroot -p password "new password"

password: old password

从MySQL4.1版本开始,MySQL服务器使用了新的算法对密码进行加密。如果从兼容性方面考虑,仍然想使用过去的加密算法,可以使用mysqladmin old-password参数,如下:

> mysqladmin -uroot -p old-password "newpassword"

Enter password: old password

经测试,修改密码命令在windows下和UNIX/Linux下有一些区别。在Linux下 password后面空一格然后输入密码,此密码用单引号或双引号或不带任何引号 结果都一样。但是在windows下此密码用双引号或不用引号结果都一样,但是如果用单引号,这个密码就是单引号加这个密码。不知道是某个版本问题还是windows下都是如此。

刚刚不小心在使用mysqladmin创建数据库时,最后加了个分号,结果发现在数据库中的数据库名字也加了个分号,比如test;,于是就郁闷了,这个数据库该怎么drop呢?其实使用mysqladmin命令很容易,但是进入数据库之后该怎么drop掉呢,研究了一番,发现只要将此数据库名字用符号``(波浪号那个键)包起来就行了,`test;`


 

1.4,mysqldump的用法

※mysqldump程序的用途是为数据库创建备份,在它生成的结果文件里包含着SQL命令。其语法如下:

>mysqldump [options] dbname > backupfile.sql    【注意mysqldump不是MySQL内部的命令】

其中options和mysql启动选项一样,此外还有许多其他的选项来调控备份工作的细节,但一般很少用得到。

备份出来的结果文件是一个文本文件。最新版本的mysqldump程序使用utf8作为自己的默认字符集。如果项使用另外一种字符集,就必须用--default-character-set=gbk选项来设置。

※mysqldump命令中带有一个 --where/-w 参数,它用来设定数据导出的条件,使用方式和SQL查询命令中中的where基本上相同,有了它,我们就可以从数据库中导出你需要的那部分数据了。
命令格式如下:
mysqldump -u用户名 -p密码 数据库名 表名 --where="筛选条件" > 导出文件路径

※ 之前的一篇文章

一、导出数据库用mysqldump命令(注意mysql的安装路径,即此命令的路径)

1、导出数据和表结构:【不是mysql里的命令】
mysqldump -u用户名 -p密码  数据库名 数据表名1 数据表名2 .... > /path/to/xxx.sql

可以指定-h,备份远程数据库,此时-u和-p都是远程数据库的信息

可以备份成压缩包,命令如下: 

mysqldump -uroot -p --host=192.168.1.139  --set-gtid-purged=OFF --single-transaction --flush-logs --master-data=2 --databases catch table1 table2 | gzip > ./source.sql.gz

#/usr/local/mysql/bin/   mysqldump -uroot -p dbname tbname> abc.sql
敲回车后会提示输入密码

2、只导出表结构
mysqldump -u用户名 -p密码 -d 数据库名 > 数据库名.sql
#/usr/local/mysql/bin/   mysqldump -uroot -p -d  dbname tbname> abc.sql

注:/usr/local/mysql/bin/  --->  mysql的data目录

  • --add-drop-table 每个数据表创建之前添加drop数据表语句。(默认为打开状态,使用--skip-add-drop-table取消选项)

  • --no-create-info, -t 只导出数据,而不添加CREATE TABLE 语句。


二、导入数据库
1、首先建空数据库
mysql>create database abc default charset utf8 collate utf8_bin; 【这一步是两种方法共同的步骤,即必须首先数据库要存在】

[  附注,与本文无关,建表语句:create table `tb_name` (..,..,..) ENGINE=InnoDB DEFAULT CHARSET=utf8;    ]

2、导入数据库
方法一:【属于mysql里的命令】
(1)选择数据库
mysql>use abc;
(2)设置数据库编码
mysql>set names utf8;
(3)导入数据(注意sql文件的路径)
mysql>source /home/abc/abc.sql;
方法二:【不属于mysql里的命令】
mysql -u用户名 -p密码 数据库名 < 数据库名.sql
#mysql -uabc_f -p abc < abc.sql

建议使用第二种方法导入。

注意:①有命令行命令 ,有mysql里面的命令  ②导出命令是mysqldump,导入命令是mysql(都是命令行下的命令)

 

 


 

2,MySQL Administrator 和 MySQL Query Browser

这是两个图形化界面,资料比较少,感觉也没学的必要,略过。

 


 

3,phpMyAdmin:在web中(浏览器中)使用

3.1,phpMyAdmin的安装:

其实phpMyAdmin就是个php工程。只有将下载后的phpMyAdmin文件夹放在apache的目录下,然后访问此目录即可。windows和Linux都是如此。

 


3.2,phpMyAdmin的配置:

在phpMyAdmin文件夹根目录里可以找到其配置文件config.inc.php(没有的话可以手动创建一个)。里面的$cfg['Servers'][$i]['auth_type'] = 'config'/'cookie'/'http';代表三种身份验证模式,config即是按照配置文件中设定的用户和明文密码登录,方便但是缺乏灵活性,无法让多位用户分别管理它们各自的数据库;其余二种则是需要在登录窗口中输入用户名和密码才能进入,可以让多位用户分别管理它们各自的数据库。


3.3,保护MySQL:

※Host字段取值是%的用户,%意味着用户可以从网络或因特网里的任何地点登录。取值为localhost表示用户只能从本地计算机去访问MySQL服务器。

※创建数据表时,对字段属性的一些说明(部分):

Field: 字段名字,如name

Type: 数据类型,如INT或VARCHAR

Length: 即类似INT(m)中的这个m。这个属性对绝大多数数据类型来说是可选的,只有VARCHAR类型的字段必须设置一个最大字符长度(最多可以是65535个字符(注意,经过自己的验证,的确是字符而不是字节!),5.0.3(不包括)之前的版本中是最多255个字符);

Collation: 设定此字段使用的字符集和排序方式(仅在不想让此字段使用在创建此字段时选择的默认字符集和排序方式的时候才需要这个字段).实际使用的时候用法如下:collate ascii_bin/utf8_bin等等。

Comment: 可以在单个字段上使用,也可以在数据表上使用。如

create table test(id int comment "我是字段的注释") default charset=utf8 comment "我是数据表的注释"

※设置外键规则:外键规则有时也称为一致性规则。注意设置外键时,两个字段的属性要完全相同!否则会报错。


 

3.4,(数据库/数据表的)导入和导出 

3.4.1,导出:

※一些导出选项的说明:(自定义导出选项)

①Disable foreign key check(禁止外键约束选项):如果正在导出带有外键规则的InnoDB数据表,应该激活这个选项。这将使phpMyAdmin在SQL文件的开头加上SET FOREIGN_KEY_CHECKS=0语句(禁用外键检查),而在文件末尾加上SET FOREIGN_KEY_CHECKS=1语句(恢复外键检查)。这样在数据库恢复过程中将不再对外键约束进行检查,不仅可以加快导入操作的速度,还可以避免因为没有按照正确的顺序创建数据表而导致导入操作执行出错。

②其他一些重要选项很容易理解,如是否要在导出的SQL文件里假如DROP TABLE IF EXISTS等字样。另外注意一个地方,如果允许一条INSERT命令插入多个数据记录,这样做更有效率,但是有可能导致INSERT语句过长而出错(相应的出错信息是got a packet bigger than 'max_allowed_packet' bytes);

③作为备份结果的SQL文件是一个UTF-8(Unicode)文件。

④导出文件的格式中有一个是CSV(comma-seperated value,用逗号隔开的数据,也可以自定义分隔符),其实就是文本文件。使用于一张表一张表的导入/导出。

 


 

3.5,服务器管理

※一些系统管理任务的命令(对应于phpMyAdmin主页上的一些按钮)

SHOW STATUS; // 显示MySQL服务器的工作状态

SHOW VARIABLES;//显示MySQL系统变量的设置情况

SHOW PROCESSLIST;// 显示当前进程表

SHOW COLLATION;//显示MySQL服务器支持的所有字符集和排序方式

 附录:phpMyAdmin的配置文件(config.inc.php)内容:


/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* phpMyAdmin sample configuration, you can use it as base for
* manual configuration. For easier setup you can use setup/
*
* All directives are explained in documentation in the doc/ folder
* or at .
*
* @package PhpMyAdmin
*/

/*
* This is needed for cookie based authentication to encrypt password in
* cookie
*/
$cfg['blowfish_secret'] = 'a8b7c6d'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */

/*
* Servers configuration
*/
$i = 0;

/*
* First server
*/
$i++;
/* Authentication type */
$cfg['Servers'][$i]['verbose'] = 'mysql wampserver';
//$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['auth_type'] = 'config';
//$cfg['Servers'][$i]['auth_type'] = 'http';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = '1234';
/* Server parameters */
$cfg['Servers'][$i]['host'] = '127.0.0.1';
$cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['compress'] = false;
/* Select mysql if your server does not have mysqli */
$cfg['Servers'][$i]['extension'] = 'mysqli';
$cfg['Servers'][$i]['AllowNoPassword'] = true;

/*
* phpMyAdmin configuration storage settings.
*/

// No warning on pmadb tables
$cfg['PmaNoRelation_DisableWarning'] = true;
//Other Settings(add myself)

//设置php脚本的最长执行时间(超大数据库的导入/导出操作),不一定有效,最终取决于php的配置文件php.ini中的max_execution_time变量,此外还有上传文件的最大长度php.ini中的upload_max_filesize变量
#$cfg['ExecTimeLimit'] = n;

//设置为true可以在导出csv文件时选择编码。貌似新版本已没有此选项了
#$cfg['AllowAnywhereRecoding'] = true;

//控制phpmyadmin数据库(此数据库涉及phpMyAdmin的一些高级/辅助功能)的用户和密码(和root设为一样),但新版中实际好像没什么用,即使都屏蔽掉,那些功能也有
$cfg['Servers'][$i]['controluser'] = 'root';
$cfg['Servers'][$i]['controlpass'] = '1234';
//如果没有把phpmyadmin单独设计成一个数据库,而是把其中的数据表放在了其他数据库里,可以用下行配置指定数据表放置的数据库名字
#$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';

//指定保存phpMyAdmin的SQL书签和历史命令的数据表
$cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
$cfg['Servers'][$i]['history'] = 'pma__history';
//指定保存 关联/引用关系 的数据表名
$cfg['Servers'][$i]['relation'] = 'pma__relation';
$cfg['Servers'][$i]['table_info'] = 'pma__table_info';
//创建PDF格式的 关联/引用关系 图
$cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
$cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
//字段内容的另类显示效果,如图片显示为图片,超链接显示为超链接等
$cfg['Servers'][$i]['column_info'] = 'pma__column_info';
?>


 

4,Microsoft Office 等办公软件与MySQL的互联

文中介绍的技术不知道现在还能不能用,但是现在有个软件叫Navicat for MySQL,很强大。可以和MS office互通。


 

三,基础知识

目录

第一章:数据库设计概论

第二章:SQL语言入门

第三章:SQL解决方案

第四章:访问安全与信息安全

第五章:GIS函数

第六章:存储过程与触发器

第七章:管理与服务器配置

第一章,数据库设计概论

1.1,参考读物:独立于具体的数据库系统而专门讨论数据库设计理论和介绍SQL语言的图书很多。

 


 

1.2,数据表类型

※在创建一个新的MySQL数据表时,可以为它设置一个类型;这种做法在其它数据库系统里是不多见的。MySQL支持多种数据表类型,它们各自有各自的特点和属性,其中最重要的3种类型是:MyISAM、InnoDB、HEAP。如果在创建一个数据表时 没有设置其类型,MySQL服务器会根据配置文件决定默认类型。默认的数据表类型由MySQL配置文件(my.ini)里的default-storage-engine决定。

#设置MySQL默认的数据表类型
#default-storage-engine=MyISAM
#default-storage-engine=InnoDB
#default-storage-engine=HEAP

 

1.2.1,MyISAM数据表

1.2.1.1,MyISAM数据表类型的特点是成熟、稳定和易于管理。只要没有特殊理由选择其他的类型,就应该选用这个类型。这种数据表类型在MySQL内部又细分为以下两种,MySQL服务器会自行选择它认为最适当的一种来使用:

①MyISAM Static(静态MyISAM):如果数据表里的字段各自都由预先定义好的固定长度,MySQL服务器将自动选择这种数据表类型。这种数据表的数据存取效率非常高,而且即使对数据表的修改非常频繁(这里指的是有大量的INSERT、UPDATE、DELETE命令)也是如此。还有,这种数据表类型 的安全性相当高,即使出现文件受损或其他问题,数据记录的提取和恢复工作也比其他类型的数据表容易。

②MyISAM Dynamic(动态MyISAM):如果在数据表的定义里出现了VARCHAR、xxxText(tinyText,Text,mediumText,longText)或xxxBLOB字段,MySQL将自动选择这种数据表类型。与静态MyISAM类型相比,这种类型的突出优点是数据表的控件需求量要小得多:存储字符串和二进制对象所需要的字节数仅仅是它们的实际长度(再加上几个字节的开销,用于记录长度)。然而缺点是,这样就使数据记录不都是同样的长度,如果记录被修改了,它们在数据库里的存储位置就可能发生变化并在原先的位置留下一个空洞(自己的理解:比如,原来两个字段的指分别占有2个字节和3个字节,现在修改第一个字段的值,其新值占有4个字节,如此原来的2个字节的位置容不下这个新值,所以新值就会在其他地方保存,而原来的这2个字节就变成了一个空洞)。于是,在数据库文件里,同一条记录的各个字段就不一定是存储在一个连续的字节快里,而是会散布到各处。当被编辑的数据表变得越来越碎片化时,数据的存取时间就会变得越来越长。因此,这种类型的数据表需要人们经常地使用SQL命令OPTMIZE TABLE或者其他优化工具来进行碎片整理(myisamchk,后面会讲到)。

1.2.1.2,MyISAM Compressed(压缩MyISAM):动态和静态MyISAM数据表都可以用myisamchk工具压缩。这种压缩的效果往往可以使数据表的空间占用量减少到原来的一半以下(与数据表的具体内容有关).虽说以后在读取数据记录时需要对它们进行解压缩,但在某些场合,数据表的访问速度甚至会变得更快----这在“低速硬盘+高速CPU”的系统上体现的尤其明显。压缩MyISAM数据表的最大缺点是它们是只读的,不能对它们进行修改。

1.2.2,InnoDB数据表

1.2.2.1,InnoDB可以看作是MyISAM的一种更新换代产品,InnoDB数据表驱动程序是MySQL的一个集成组件,由一家名为InnoDB的独立公司提供技术支持,它至少增加了以下几种新功能:

①事务。这将允许把几条有着内在逻辑关系的SQL命令当作一个整体执行。如果在执行时发生错误,所有的命令(而不仅仅是触发错误的命令)都将失效,就好像从未执行过这些命令一样。MySQL支持ANSI-SQL/92标准里定义的全部4种事务级别(READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE),后面会有在详细介绍。

②数据行级锁定机制。在执行一个事务的时候,InnoDB数据表的驱动程序使用的是它自己内建的数据行级锁定机制(不是MySQL提供的数据表级锁定机制)。也就是说,在事务过程中,数据表是不会被锁定的,其他用户仍可以访问它,被锁定的只是正在接收事务处理的数据记录(而MyISAM数据表在执行LOCK TABLE命令期间会被整个锁定)。如果有许多用户正在同时对一个大数据表进行修改,数据行级锁定机制将会大大提高人们的工作效率。InnoDB驱动程序能够自动识别“死锁”现象(两个进程各自占用着一项对方需要的资源,同时又在等待对方先释放所占用的资源,结果是谁也继续执行)并自动终止两个进程中的一个。

③外键约束条件。如果在数据表之间定义了关系,InnoDB驱动程序可以自动保证数据表的引用一致性在执行过DELETE命令之后也能保持。用数据库的术语来讲,这一功能叫做外键约束条件。

④崩溃恢复。在发生崩溃后,InnoDB数据表能够迅速地恢复到一个稳定可用的状态(前提是计算机的文件系统没有被破坏).

1.2.2.2,InnoDB数据表的问题和缺陷

①表空间的管理。MyISAM数据表驱动程序把每个数据表分别保存在它自己的文件里,这些文件会根据实际情况增大或缩小。InnoDB数据表驱动吃挂失却是把所有的数据和索引都保存在一个表空间(tablespace)里。表空间是由一个或多个文件构成,它们形成了一个虚拟的文件系统,这些文件在被创建之后只能增大,不能缩小。

②数据记录的长度。InnoDB数据表中的单条数据记录最多可以占用8000个字节的空间。例外情况是Text和Blob数据列,这两种数据类型只有前512个字节是随其他数据列一起存储的数据库里的,超过这个长度的数据将被存放 在表空间的其他页面。

③存储空间的占用量。InnoDB数据表的空间占用量要比同样内容的MyISAM数据表大很多(最多时会有后者的2倍)。

④全文索引。InnoDB数据表不支持全文索引(full-text index)。注释:MySQL5.6之后InnoDB也支持全文索引了。

⑤GIS数据。InnoDB数据表不能用来保存二维地理数据。

⑥COUNT问题。因为支持事务,InnoDB数据表驱动程序在统计一个数据表里的记录个数时经常会遇到困难,所以在InnoDB数据表上执行SELECT COUNT(*) FROM TABLE命令的速度比的MyISAM数据表上慢很多。

⑦数据表锁定。InnoDB驱动程序在执行事务时使用的是它自己的锁定算法。因此,应该尽量避免使用LOCK TABLE...READ/WRITE命令。应该使用SELECT...IN SHARE MODE或SELECT...FOR UPDATE 命令----它们将只锁定个别记录而不是锁定整个数据表

⑧mysql数据表。用于管理MySQL访问权限的mysql数据表不能被转换为InnoDB数据表。它们必须是MyISAM格式。

1.2.2.3,选择MyISAM还是InnoDB?

首先,同一个数据库里的不同数据表可以是不同的类型,也就是说,MyISAM数据表和InnoDB数据表可以存在于同一个数据库里。如果希望以最节约空间和时间的方式来管理数据表,MyISAM数据表就应该是首选。如果应用程序需要用到事务,需要更高的安全性,或者需要允许很多用户同时修改某个数据表里的数据(此时,InnoDB不必锁定整个数据表的优势让效率更高 ),InnoDB数据表就更指的考虑。

1.2.3,HEAP(堆栈中的堆)数据表

HEAP数据表只存在于内存中(不是硬盘上)。它们使用了一个散列索引(hash index,又叫哈希索引),所以数据记录的存取速度非常快。HEAP数据表的主要用途是充当临时数据表。HEAP数据表适用于数据量相对较小,但对访问速度要求恢复过程的场合。请注意,因为HEAP数据表只存在于内存,所以一旦MySQL服务器停止运行,HEAP数据表也就消失了。从这个意义上讲,HEAP数据表是一种临时性的数据表。但注意它和特意使用CREATE TEMPORARY TABLE命令或是MySQL为类保存中间结果而临时创建的数据表(下面马上就讲到)是有区别的:HEAP数据表对于来访问同一个数据库的其他MySQL连接是可见的,在这个客户端连接以外中断时也不会丢失(原因时因为,数据是存在于MySQL服务器程序开辟的内存上的,对所有访问MySQL服务器的客户端口是可见的,而且客户端断开连接也不会影响MySQL服务器的内存)。HEAP数据表的最大长度由MySQL配置文件里的max_heap_table_size参数决定。

1.2.4,临时数据表(这里是指特意使用CREATE TEMPORARY TABLE命令或是MySQL为了保存中间结果而临时创建的数据表)

这种临时数据表并不是一种数据表类型,其类型可以是前面介绍过的任意一种。临时数据表与其他MySQL数据表是分开保存的,MySQL会把它们存放到一个临时子目录里去,这个临时子目录在Windows环境下通常是C:\Windows\Temp,在UNIX/Linux环境下通常是/tmp或是/var/tmp或/usr/tmp,这个子目录可以在MySQL服务器启动时在配置文件里设置。另外,这种数据表对于访问同一个数据库的其他MySQL连接是不可见的(即某个临时数据表是由某个客户端独自拥有),所以两个不同的客户端可以在同一个数据库里使用相同的名字创建临时数据库而不会发生冲突。

1.2.5,其他的数据表类型

如果想知道自己的MySQL服务器支持哪些数据表类型,可以用SHOW ENGINES命令来查看。

 


 

1.3,数据表文件

可以在启动MySQL服务器时在配置文件里为 数据库文件指定一个存放位置(在UNIX/Linux下通常时/var/lib/mysql,在Windows下通常是C:\....\MySQL Server n.n\data)。

配置文件里指定数据库文件存放目录

datadir=D:/wamp/bin/mysql/mysql5.6.17/data

每个数据库在datadir目录下都由一个文件夹,下面分别介绍MyISAM和InnoDB类型的数据表存放方法:

①两者都共同拥有的:每个数据库在datadir目录下有一个同名文件夹,数据库文件夹下都有:

一个db.opt(MySQL4.1版本开始)文件,此文件记录了整个数据库的结构定义和设置(如默认字符集和默认排序方式);

每个数据表都对应一个*.frm文件,这个文件记录了数据表的结构定义(字段名称,字段的数据类型等)

②MyISAM数据表类型独有的:

MySQL还为每个MyISAM数据表创建两个文件:

一个是datadir/dbname/tablename.MYD文件,此文件存放MyISAM数据表的数据

另一个是datadir/dbname/tablename.MYI文件,用来存放MyISAM数据表的全部索引

③InnoDB数据表类型独有的:

根据MySQL配置文件中的innodb_file_per_table选项的设置情况,InnoDB数据表既可以各自存为一个文件,也可以统一存放在一个表空间(tablespace)里。表空间的存放位置和名字由配置设置决定。

MySQL默认的安排是把InnoDB数据表的数据和索引单独存放在一个文件datadir/dbname/tablename.idb里,但是把表空间和撤销日志(undo log)存放在datadir/ibdata1、-2、-3等文件里,把InnoDB日志数据存放在datadir/ib_logfile0、-1、-2等文件里。

如果用户还为数据表定义了触发器(trigger,后面会讲到),MySQL会把它们的代码存放在datadir/dbname/tablename.TRG文件里(以后可能会变化)。

附注:innodb_file_per_table选项相关,此选项在配置文件里的[mysqld]模块中配置,对于wampserver则是在[wampmysqld]模块中

 

InnoDB 引擎独立表空间 innodb_file_per_table

 

使用过MySQL的同学,刚开始接触最多的莫过于MyISAM表引擎了,这种引擎的数据库会分别创建三个文件:表结构、表索引、表数据空间。我们可以将某个数据库目录直接迁移到其他数据库也可以正常工作。然而当你使用InnoDB的时候,一切都变了。
InnoDB 默认会将所有的数据库InnoDB引擎的表数据存储在一个共享空间中:ibdata1,这样就感觉不爽,增删数据库的时候,ibdata1文件不会自动收缩,单个数据库的备份也将成为问题。通常只能将数据使用mysqldump 导出,然后再导入解决这个问题。
在MySQL的配置文件[mysqld]部分,增加innodb_file_per_table参数。
可以修改InnoDB为独立表空间模式,每个数据库的每个表都会生成一个数据空间。
独立表空间:
优点:
1. 每个表都有自已独立的表空间。
2. 每个表的数据和索引都会存在自已的表空间中。
3. 可以实现单表在不同的数据库中移动。
4. 空间可以回收(除drop table操作处,表空不能自已回收)
a) Drop table操作自动回收表空间,如果对于统计分析或是日值表,删除大量数据后可以通过:alter table TableName engine=innodb;回缩不用的空间。
b) 对于使innodb-plugin的Innodb使用turncate table也会使空间收缩。
c) 对于使用独立表空间的表,不管怎么删除,表空间的碎片不会太严重的影响性能,而且还有机会处理。
缺点:
单表增加过大,如超过100个G。
结论:
共享表空间在Insert操作上少有优势。其它都没独立表空间表现好。当启用独立表空间时,请合理调整一 下:innodb_open_files 。
InnoDB Hot Backup(冷备)的表空间cp不会面对很多无用的copy了。而且利用innodb hot backup及表空间的管理命令可以实现单现移动。

1.innodb_file_per_table设置.开启方法:
在my.cnf中[mysqld]下设置
innodb_file_per_table=1
2.查看是否开启:
mysql> show variables like ‘%per_table%’;
3.关闭独享表空间
innodb_file_per_table=0关闭独立的表空间
mysql> show variables like ‘%per_table%’;
更多Mysql Innodb 引擎优化 http://linux.chinaunix.net/techdoc/database/2009/04/28/1109193.shtml 


 

1.4,MySQL数据类型

1.4.1,整数(xxxINT)

1.4.1.1,默认情况下,INT数据类型既包括正数,也包括负数。通过为INT定义属性UNSIGNED可以将其取值范围限定于正数。

mysql学习笔记_第3张图片

关于整型数据来说,可选参数m的解释:m表示数据在显示时显示的最小长度,它的作用是帮助MySQL和各种用户操作界面把查询结果以一种整齐易读的格式显示。比如,tinyint(4)表示数据显示时最小要显示4位,如果原数据大于4位,没有任何影响,该显示几位就显示几位;如果数据小于4位,那么显示时至少要显示4位。但是要注意,这个参数要产生效果必须和zerofill属性一起使用(而且要写在一起),不足4位的数据用0填充至4位。自己在验证时还发现,一旦定义了zerofill属性,那么这个整型将自动转变为UNSIGNED的类型。总结一下,这个可选参数m只在一种情况下有效,即数据位数小于m且定义了zerofill属性。在建表时,MySQL会自动分配长度:INT(11)、TINYINT(4)、SMALLINT(6)、MEDIUMINT(9)、BIGINT(20)。所以就用这些默认的显示长度就行了,可以说参数m没有什么使用价值。

1.4.1.2,AUTO_INCREMENT整数:

使用AUTO_INCREMENT属性需要注意以下几个问题:

△每个数据表最多只能由一个AUTO_INCREMENT字段。

△这个属性必须和NOT NULL、PRIMARY KEY(或者UNIQUE属性)同时使用。即定义为AUTO_INCREMENT的字段必须要是个键。NOT NULL如果不写,MySQL会自动帮你补上。

△MySQL的这种ID值自动生成机制只在用户使用INSERT命令插入新记录并且没有为ID字段明确地给出一个值或给了一个NULL 值时才起作用。如果用户显性的给出了一个具体的值,那么将会使用显性给出的值生成一条新数据记录。

△如果想知道MySQL在刚插入数据记录里生成的AUTO_INCREMENT值时多少,在执行完INSERT命令之后(但还是在本次连接或本个事务里),执行SELECT LAST_INSERT_ID()命令(允许中间由其他操作,获取的始终时最近的那个自动插入的ID)。

△如果AUTO_INCREMENT计数器达到了它的最大值(不同的整数数据类型由不同的最大值),将不再继续递增。

1.4.1.3,关于关键字BOOL和BIT:MySQL关键字BOOL是TINYINT的同义词。MySQL5.0.2及之前的版本里的BIT也是如此。从5.0.3版开始,BIT变成了一种可以存储多达64位二进制数值的新数据类型。

1.4.1.4,浮点数(FLOAT和DOUBLE):这里把浮点数归到整数一节讲,有点奇怪。

从MySQL3.23版开始,FLOAT和DOUBLE类型一直分别对应着IEEE标准所定义的单精度浮点数和双精度浮点数,大多数程序设计语言都支持这两种数据类型。MySQL中的单精度浮点数FLOAT有8位精度(4个字节), 双精度浮点数DOUBLE有16位精度(8字节)。

FLOAT(m, d) / DOUBLE(m, d)  数值是用m和d两个可选参数来设置。其中m是数字的总个数,d是小数点后面的数字个数。例如,FLOAT(5,3)表示此单精度浮点数整数位有2位,小数位有3位。因此其能表示的最大数值是99.999,最小数值是-99.999。超出范围的数字都将显示为99.999或-99.999。另外,非常大或非常小的数据将使用科学计数法写出。

另外:MySQL中的关键字REAL(m, d)是DOUBLE的同义词。

 

1.4.2,(Fixed-Point Numbers)定点数:(DECIMAL)

MySQL在把数据保存为FLOAT和DOUBLE数据类型的时候会自动进行必要的舍入。如果带来的误差不可接收(比如在处理财务数据的时候),就应该选用DECIMAL数据类型。DECIMAL数据类型以字符串的形式来保存数据,并且不允许使用指数形式,所以将占用更多的空间。

DECIMAL(m,d): m表示总的数字位数,d表示小数位的数字位数。

MySQL中的关键字NUMERIC, DEC是DECIMAL的同义词。

关于FLOAT和DOUBLE类型的数据如何带来误差以及和DECIMAL数据类型的区别参见如下链接:http://www.cnblogs.com/everest33Tong/p/7794196.html

 

1.4.3,日期和时间(DATE / TIME / DATETIME / TIMESTAMP)

MySQL支持的日期和时间数据类型
MySQL数据类型 含义  
DATE '2017-11-06'格式的日期值,取值范围:0000-00-00~9999-12-31 (3个字节)  
TIME '23:59:59'格式的时间值,取值范围:±838:59:59 (3个字节)  
DATETIME

'2017-11-06 23:59:59'格式的DATE 加 TIME组合,取值范围:0000-00-00 00:00:00 ~ 9999-12-31 23:59::59

注意:如果mysql提示0000-00-00的时间默认值不对,那么应该是sql_mode中禁用了时间为0值。查询一下sql_mode的值可以看到:

sql_mode | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,

NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

只要在配置文件中的[mysqld]中添加:

sql_mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
并重启MySQL即可。

 
TIMESTAMP  格式和DATETIME相同,但取值范围为:
  • mysql官方文档解释:timestamp的范围:1970-01-01 00:00:01UTC~2038/01/19 3:14:07UTC,
  • 我们是东八区,所以我们的timestamp的范围:1970-01-01 8:00:01UTC~2038/01/19 11:14:07UTC
 
YEAR  年份,取值范围:最大值2155,最小值懒得去验证了. (一个字节)  
     

 1.4.3.1,MySQL对日期和时间数据进行的合法性检查有MySQL系统变量sql_mode控制(后面会讲到)。关于这个变量的详细介绍请参见:http://www.cnblogs.com/everest33Tong/p/7795172.html

1.4.3.2,在MySQL早期版本中,TIMESTAMP值的格式是YYYYMMDDHHMMSS而不是像现在这样的YYYY-MM-DD HH:MM:SS。如果需要转换成老格式,可以在此字段上加上一个0(比如,SELECT ts+0 FROM table)。另外,MySQL提供了几个函数用来处理日期/时间值的格式。其中以DATE_FORMAT()函数用法最为灵活,后面会讲到。

1.4.3.3,TIMESTAMP时间戳在创建的时候可以有多重不同的特性,如:

1.在创建新记录和修改现有记录的时候都对这个数据列刷新:

1
TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

这里直接写TIMESTAMP和其效果一样,但是新发现新版本MySQL的并不一样,不写就相当于没有默认值也不会在更新的时候自动更新。如果后面更新时某条记录时间不需要改变,可以使用 UPDATE tbname SET data='xxx', ts=ts WHERE cond这样的命令。

2.在创建新记录的时候把这个字段设置为当前时间,但以后修改时,不再刷新它:

1
TIMESTAMP DEFAULT CURRENT_TIMESTAMP

3.在创建新记录的时候把这个字段设置为0,以后修改时刷新它:

1
TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

4.在创建新记录的时候把这个字段设置为给定值,以后修改时刷新它:

1
TIMESTAMP DEFAULT ‘yyyy-mm-dd hh:mm:ss'ON UPDATE CURRENT_TIMESTAMP

1.4.3.4,关于为什么timestamp的取值范围是那么规定?

在看下面文章之前,可以做个试验:

select pow(2,31)-1;发现结果也是2147483647。//2的31次方

然后select unix_timestamp('2038-01-19 11:14:07');发现结果是 2147483647;//这是timestamp的最后一秒(东八区时区)

然后select unix_timestamp('2038-01-19 11:14:08');发现结果是 0; //超出timestamp的范围了

然后select unix_timestamp('1970-01-01 8:00:01');发现结果是1;//这是timestamp的第一秒(东八区时区)

然后select unix_timestamp('1970-01-01 8:00:00');发现结果是0. //timestamp的第 “0”秒(东八区时区).

摘自:http://blog.csdn.net/crj_9527/article/details/50789849

从数据文件看timestamp范围限制

  • 创建表:
mysql> desc test_timestamp1;
+-------+-----------+------+-----+---------+-------+
| Field | Type      | Null | Key | Default | Extra |
+-------+-----------+------+-----+---------+-------+
| time  | timestamp | YES  |     | NULL    |       |
+-------+-----------+------+-----+---------+-------+
  • 插入数据,并查询,mysql官方文档解释:timestamp的范围:1970-01-01 00:00:01UTC~2038/01/19 3:14:07UTC,
  • 我们是东八区,所以我们的timestamp的范围:1970-01-01 8:00:01UTC~2038/01/19 11:14:07UTC,测试很简单:
mysql> insert into test_timestamp1 values('2038/01/19 11:14:07');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_timestamp1 values('2038/01/19 11:14:08');
ERROR 1292 (22007): Incorrect datetime value: '2038/01/19 11:14:08' for column 'time' at row 1

mysql> insert into test_timestamp1 values('1970-01-01 8:00:01');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test_timestamp1 values('1970-01-01 8:00:00');
ERROR 1292 (22007): Incorrect datetime value: '1970-01-01 8:00:00' for column 'time' at row 1
  • 为什么有这样的限制?可以从数据文件中找到答案:
mysql> select * from test_timestamp1 limit 2;
+---------------------+
| time                |
+---------------------+
| 2038-01-19 11:14:07 |
| 2038-01-19 11:14:06 |
+---------------------+
2038-01-19 11:14:07
查看表空间文件:
hexdump -C -v test_timestamp1.ibd|more
0000c1a0  00 00 00 07 75 0b 00 00  01 43 f1 16 e1 00 00 01
0000c1b0  7d 01 10 7f ff ff ff 00  00 00 68 00 1d 00 00 00
0000c1c0  07 75 0c 00 00 01 43 f1  17 e2 00 00 02 4e 01 10 
0000c1d0  7f ff ff fe 00 00 00 70  00 1d 00 00 00 07 75 0d 
0000c1e0  00 00 01 43 f1 7c b4 00  00 02 2a 01 10 7f ff ff 
  • 猜测7f ff ff fe(01111 1111 .... 1110)就是2038-01-19 11:14:06,7f ff ff ff(01111 1111 .... 1111)(最高位是符号位?)就是2038-01-19 11:14:07,为什么这么说?
做个简单的查询:
mysql> select unix_timestamp('2038-01-19 11:14:07');
+---------------------------------------+
| unix_timestamp('2038-01-19 11:14:07') |
+---------------------------------------+
|                            2147483647 |
+---------------------------------------+
2147483647就是"2038/01/19 3:14:07UTC"减去"1970-01-01 8:00:01 UTC"的秒数,也就是说实际上mysql在存储时间戳的时候,会求取32位的整数,存储在磁盘上。
mysql> select pow(2,31)-1;
+-------------+
| pow(2,31)-1 |
+-------------+
|  2147483647 |
+-------------+

1.4.4,字符串(CHAR / VARCHAR / xxxTEXT)

1.4.4.1, 说明一点:xxxTEXT和xxxBLOB 类型的数据不能有默认值。

mysql学习笔记_第4张图片

说明一点:经过自己的验证,参数n指的是字符个数,而不是字节数。也就是说,CHAR(5)可以容纳5个英文字母,也可以容纳5个汉字字符,即使每个汉字占用的是3个字节。

1.4.4.2, CHAR类型

参考文章:http://www.yiibai.com/mysql/char-data-type.html

CHAR类型的字符串长度是有严格限制的。不管字符串的实际长度是多少,CHAR(20)字段在每条记录里都将占用20个字节。

如果存储的数据是固定大小,则应使用CHAR数据类型。这种情况下,与VARCHAR相比,您将获得更好的性能。

当存储CHAR值时,MySQL将其值与空格(在值后面加)填充至声明的长度。而在查询CHAR值时,MySQL会删除尾部的空格(注意:如果设置了变量sql_mode的值为 PAD_CHAR_TO_FULL_LENGTH,则MySQL将不会删除尾部空格,此时查询出来的此字段的长度将永远固定为指定的n值,因为不足的长度将会被自动在尾部补全空格)。注意值前部的每个空格视为正常的单个字符即可,不受任何影响。

1.4.4.3,VARCHAR 和 xxxTEXT类型:

※VARCHAR和xxxTEXT类型的字符串其长度是可变的,它们占用的存储空间由它们的实际长度决定。VARCHAR和TEXT类型看起来似乎一样----两个都是可以存储多达65535(216-1)个字符的字符串数据类型,但是在一些细节方面确是有区别的:VARCHAR(n)数据列的最大字符长度n必须在声明字段时设置,而xxxTEXT类型的字段不允许设置一个最大长度(唯一的限制是特定文本类型本身的最大长度);

※VARCHAR类型的值其前导空格和尾部空格都不会被删除,每个空格都视为一个普通的字符即可。

※BINARY属性:如果给CHAR和VARCHAR类型的字段加上可选的BINARY属性,MySQL就会把它们视同BLOB字段来处理。BINARY属性带来的好处是:MySQL在排序时将把字符视为二进制(而不是字母),而这样就可以把字母的大小写形式区分开。这在没有引入BINARY属性时是做不到的。与千变万化的普通字符串相比,二进制字符串的内部管理工作更简单,需要花费的时间更短。自己试验了一下,Ubuntu下MySQL5.5.54,对文本类型的字段(CHAR/VARCHAR/xxxTEXT)使用binary属性,相当于给此字段使用CHARACTER SET charactername COLLATE sortorder(其中可以简写为CHARSET).

附注:与字符集有关的基本概念

一,MySQL中所有的文本字段都允许使用CHARSET charactername COLLATE sortorder属性来指定一种字符集和排序方式。字符集回答了使用什么样的编码来表示各种字符的问题。128个英文ASCII字符在绝大多数字符集里的编码都是一致的(如字母A的编码是65),问题主要集中在如何表示各国语言中的特有字符方面。

□□ASCII码字符集。单字节字符集,范围是0x00-0x7F(127)。其他字符集都会兼容此字符集。

□□Latin字符集。也是单字节字符集。范围是0x00-0xFF(255)。前128个字符就是ASCII码,后面的128个字符是扩展。有几种Latin字符集得到了广泛的应用,它们是:

  ①ISO-8859-1,又叫Latin1字符集,收录了西欧国家常用的所有字符,平常说的Latin字符集一般都是指这个;

  ②ISO-8859-2,也叫Latin2字符集,收录了来自中欧和东欧语言的字符。

  ③ISO-8859-15,也叫Latin0或Latin9字符集,和Latin1完全一样,只是增加了一个欧元符号。

这些字符集都存在着一个明显的问题:它们当中没有一个能把所有欧洲语言里的所有字符都收录齐全,更不用说是亚洲的语言了。

□□Unicode字符集。为了可以包容世界上所有的字符,某世界标准组织发布了Unicode字符集。基本的Unicode字符集(即第0个平面,目前总共17个平面)是双字节的, 有65536个字符。当然65536个字符只是包容了世界上最常用的字符,还有一些字符并没有包含进去,这就是Unicode的其他平面做的事了。

二,MySQL的字符集支持能力

从MySQL4.1开始,可以为每个字段分别指定一种字符集和排序方式,如果没有为某个字段指定一个字符集和排序方式,它将使用数据表、数据库或MySQL服务器的默认字符集--这取决于哪一个级别上有默认设置。字符集和排序方式的完整清单可以通过执行SQL命令

SHOW COLLATION

获得。一种字符集只能与与之对应的几个排序方式配合使用。在命令结果中,每种字符集的默认排序方式由Default列里的Yes标明。下表列出了其中的几种:ci应该是case insensitive,cs是case sensitive.

mysql学习笔记_第5张图片

 查看当前服务器正在使用的字符集:show variables like "character_set_server";

查看当前服务器正在使用的校对规则: show variables like "collation_server";

查看当前服务器数据库正在使用的字符集:show variables like "character_set_database";

查看当前服务器数据库正在使用的校对规则:show variables like "collation_database";

附录:

mysql 的默认字符集 latin1 是为什么会支持中文?!

初步分析表明,是的,确实支持中文!(是初步的结论,只做了初步的分析)

  1. 先来看看latin1 (参考百度百科)

  Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。

  ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。 

  ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中。

   因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。 

2. 稍微再想想字符集

    是的,不用纠结太多了,如果数据库内表的字符集是latin1,那么默认情况下中文也可被支持!

    · latin1覆盖了所有单字节的值,任何其他的码流都可以被看做latin1 

    · 把一个gbk编码的串写入latin1的表,不会有任何问题,保存的是原封不动的字节流 

    · 从表中读取已写入的串也不会有任何问题,且读出的字节流就和当初写入的完全一致

读取出来以后,如果在终端下,就会理解成locale类型(如果locale系gbk,当时写入的gbk中文串可正常回显) 

读取出来以后,如果要写入文件,则文件编码方式即当时写入的字节流编码,如gbk写入的,读出存入文件后,文件编码也是gbk!但是如果混着写(utf-8 + gbk),那编辑器就犯蒙了,就可能会显示会有乱码。

注: 纯文本文件大多无文件头,编辑器是通过字节流自己识别编码方式和字符集的 

3. 综上,建DB和访问DB时如果都采用默认的latin1,那就不仅仅支持中文,而是支持任意的编码方式! 

附送几个数据库中文编码的经验教训:

1. 基于可维护的角度,虽然latin1没什么问题,但是还是尽量换成utf8或者gb系列 

2. 出现乱码时:

SHOW VARIABLES LIKE 'character%'

SHOW VARIABLES LIKE 'collation_%';

a、要保证数据库中存的数据与数据库编码一致,即数据编码与character_set_database一致;

 b、要保证通讯的字符集与数据库的字符集一致,即character_set_client, character_set_connection与character_set_database一致;

c、要保证SELECT的返回与程序的编码一致,即character_set_results与程序编码一致;

d、要保证程序编码与浏览器、终端编码一致

3. 要想简单一点的话,就将各个字符集都设为一致的,写入mysql的配置文件,每次用客户端都设置一下字符集(set names 'xxx'),写入和读取时要记得确保字节流的编码是ok的

1.4.5,二进制数据(xxxBLOB和BIT和BINARY和VARBINARY)

1.4.5.1,BLOB(Binary Large OBject二进制大对象)数据类型与TEXT数据类型有着几乎完全一样的属性,唯一的区别是TEXT数据通常是按照文本模式进行比较和排序的,而二进制数据则是根据它们的二进制编码进行比较和排序的。

    是否应该在数据库里存放二进制数据一直是个容易引起争论的问题。有不少人认为应该把二进制数据(如图像)保存为外部文件,数据库指用来保存这些文件的链接。

    把短小的数据(字符串、整数等)与长的数据(BLOB和长文本)混合存放在同一个数据表是一种非常不好的做法,因为这会导致所有数据记录的存取速度变慢。

    此外,BLOB数据在正常操作情况下只能作为一个整体来读出。如果某个BLOB数据的长度是800KB,想直接读取它的最后100KB是不可能的。BLOB数据必须以一个整体来读写和传输。

下表列出了MySQL所支持的二进制数据类型:

mysql学习笔记_第6张图片

说明:经自己验证,对于二进制数据,能存储的最大值都是以字节为单位的(除了BIT是以位为单位),这和字符串类型的数据(按字符而非字节)不一样。

1.4.5.2,BIT数据类型

早期的MySQL版本,BIT只是TINYINT(1)的同义词。而现在BIT表示最大宽度可达64位的二进制数据。从MySQL5.0.3开始新增了一条用来写出二进制数据的新语法:b'0101'。直接使用SELECT查询BIT类型的字段时一般是无法正确显示出来的。可以使用

SELECT bitcolumn+0

命令把二进制值转换为整数显示出来,或者使用

SELECT BIN(bitcolumn) 或 SELECT BIN(bitcolumn+0)

命令显示出二进制值。如果插入BI字段的数值引起了下溢出或上溢出,所有的二进制位都将被设置为1。如果在BIT类型字段上存储汉字,如在utf8字符集的表上的BIT(33)字段上存储了一个汉字"我",则各种查询结果如下所示:

mysql> select a,a+0,bin(a),bin(a+0) from a;
+-------+----------+--------------------------+--------------------------+
| a | a+0 | bin(a) | bin(a+0) |
+-------+----------+--------------------------+--------------------------+
| 我 | 15108241 | 111001101000100010010001 | 111001101000100010010001 |
| 我 | 15108241 | 111001101000100010010001 | 111001101000100010010001 |
| 我 | 15108241 | 111001101000100010010001 | 111001101000100010010001 |
| 我 | 15108241 | 111001101000100010010001 | 111001101000100010010001 |
| 我 | 15108241 | 111001101000100010010001 | 111001101000100010010001 |
| 我 | 15108241 | 111001101000100010010001 | 111001101000100010010001 |
| 我 | 15108241 | 111001101000100010010001 | 111001101000100010010001 |
+-------+----------+--------------------------+--------------------------+

实际存储的是汉字“我”的UTF-8编码(E6 88 91)。

1.4.5.3,BINARY和VARBINARY类型

※BINARY和VARBINARY的区别就和CHAR和VARCHAR的区别一样。

※BIT类型是按位存储二进制数据的,其中存储的内容(数字,字符(如汉字)等)都可以直接转化为二进制表示的值(bin()函数),也可以转化为十进制表示的值(+0)。而BINARY、VARBINARY、xxxBLOB是一样的,都是按字节存储二进制数据的,其中存储的字符(如汉字)是不能用bin()函数转化为二进制值的。但猜想BIT和xxxBLOB的实质应该是一样的。

1.4.5.4,xxxBLOB数据类型

※可以在配置文件中设置BLOB类型允许的最大文件大小:(Windows下 my.ini文件;Linux下/etc/mysql/my.cnf文件)

[mysqld]
max_allowed_packet = 16M //不同于[mysqldump]下的max_allowed_packet

※TEXT和BLOB的区别:

①TEXT最大存储是按字符计算,BLOB最大存储是按字节存储;

②TEXT是非二进制字符串,并且需要指定字符集并按照该字符集进行校验和排序。只能存储纯文本,可以看做是VARCHAR在长度不足时的扩展。BLOB存储的是二进制数据,因此无需字符集校验,是直接根据其二进制编码进行比较和排序的,BLOB可以看做是VARBINARY在长度不足时的扩展。BLOB除了存储文本信息外,由于是二进制 存储格式,所以还可以保存图片,PDF文档等二进制文件。

※BLOB数据类型建立索引

xxxBLOB和xxxTEXT类型的字段是无法直接建立索引的,因为是变长的。所以要给这两种数据类型建立索引就需要指定索引长度。具体用法如下:

ALTER TABLE tb_name ADD UNIQUE KEY key_name(blobcolumn(5));

注意点:key_name不能加单引号或双引号,但是可以加波浪线上的引号``。

另外,二进制数据类型都能区分大小写,而字符串类型(char/varchar/text等)的如果使用校对(collation)方式为utf8_general_ci(Case Insensitive)则是不能区分出大小写的,也就是说如果给一个使用了utf8_general_ci校对方式的char字段设置了unique key,那么'a'和'A'不能同时插入,会提示重复的键。但是如果使用的校对方式为utf8_bin,则是可以区分出大小写的。

※如何在MySQL数据库中使用BLOB存取图片信息(使用PHP)

基本思路就是使用php的file_get_contents函数或 fopen/fread函数读取图片的二进制内容,然后插入MySQL数据库的BLOB字段中(把读取的二进制内容当做普通字符串一样即可),需要注意的是:由于读取的二进制内容很多乱七八糟的符号,所以要加上addslashes()函数(此函数会在一下字符前面加上反斜线:单引号(')、双引号(")、反斜线(\)与 NUL(NULL 字符))。然后读取时直接读取出BLOB字段中的内容,利用PHP的header('content-type: image/jpg');来显示出这个图片。

部分代码如下:

首先创建数据库:

CREATE TABLE files(

`id` int not null auto_increment primary key,

`mime` varchar(20) not null default '',

`data` blob

) engine=innoDB;

然后随便插入一条数据:insert into files values(1, 'image/jpg', 'img blog');

PHP 脚本代码如下:

conn = new mysqli($this->db_host, $this->db_user, $this->db_password, $this->db_name);
            $this->conn->query("SET NAMES UTF8");
        //    echo "SUCCESS";
        } catch(mysqli_sql_exception $e)
        {
            echo "Error:";
            echo $e->getMessage();
            echo $e->getCode();
        }
    }

    function updateBlob($id, $filepath, $mime)
    {
        $blob = fopen($filepath, 'rb');
        $data = addslashes(fread($blob, filesize($filepath)));//addslashes is the key!!!
        $sql = "UPDATE files SET mime = '$mime',data = '$data' WHERE id = $id;";
        $query = $this->conn->prepare($sql);
        $result = $query->execute();
        return $result;
//        var_dump($sql, $result, $this->conn->error);
    }

    function readBlob($id)
    {
        $sql = "select id, mime, data from files where id=$id";
        $query = $this->conn->query($sql);
        $result = $query->fetch_assoc();
        return $result['data'];
    }

    function __destruct()
    {
        $this->conn = null;
    }
}
$id = $_GET['id'];
$bd = new BlobDemo;
$bd->updateBlob(1,'./test1.jpeg','image/jpeg');
$read = $bd->readBlob($id);
header("content-type: image/jpeg");
echo $read;
?>

HTML代码如下:




    


    
THIS IS A PICTURE OF SNOW! I LOVE SNOW I LOVE WINTER ILOVEYNWA

1.4.6,其他数据类型(ENUM,SET等)

ENUM和SET数据类型是MySQL的一个特色,它们让MySQL服务器以一种非常有效率的方式对字符串的集合进行排列组合。(但同时也是它的一个缺点,因为大多数其他数据库系统根本 不知道ENUM和SET是什么,如果需要把MySQL数据库移植到其他数据库系统去的时候会很复杂。因此多创建一个关联数据表来取代ENUM和SET数据列的做法往往更有实用价值)。

ENUM数据类型定义的是一个字符串集合(注意,ENUM和SET的值只能是字符串的排列组合),ENUM的成员最多可以有65535个。按照集合中的字符串的顺序,每个字符串分别对应1,2,3,4,5,6,7......,MySQL实际存入ENUM数据列的正是这些编号而不是那些字符串本身。数据表中的ENUM字段的取值只能是这个集合中的某一个成员。

在设计字符串比较操作的查询里,MySQL不区分ENUM数据的字母大小写情况(如果想区分大小写有两种方法:①给ENUM字段加上BINARY属性②给ENUM字段加上可以区分大小写的校验规则,如collate utf8_bin)。除了在集合里预先定义的那些字符串,空白字符串(即两个单引号或两个双引号)总是可以存入ENUM字段。

 


SET数据类型采用了类似的思路,但允许数据表中的SET字段的取值是集合成员的任意组合(但数量不得超过64个);另外,SET中的字符串按照顺序分别和2的幂(1,2,4,8,16,32......)相对应。即,如果一个SET字段取值为7,则表示是前三个字符串的组合(以逗号隔开)。这么做的好处是可以利用各种二进制按位比较操作处理SET数据,弊端是空间浪费巨大(一个字节只能对应8个选项)。SET类型的空间占用量比ENUM的大,最多可以有64个字符串参加组合(按每个SET字段占用8个字节计算)。

在把多个字符串的组合存入SET字段的时候,字符串之间必须用逗号隔开(并且不允许有空格,否则带空格的部分会被删除)。

在查询命令里使用"="操作符比较SET数据将会是完全匹配,如果想查找某SET字段中是否包含某个字符串,可以使用MySQL函数FIND_IN_SET(searchstr, setstr),这个函数返回给定字符串searchstr在SET集合setstr里的定义顺序(第一个序号为1,接着是2,3,4,...)。例如:

SELECT * FROM tbname WHERE FIND_IN_SET('xxx', colSET)>0;

 


ENUM和SET的值在MySQL内部被表示为整数而不是字符串。如果想查询这些整数的值可以使用 SELECT x+0 FROM table这样的命令,SELECT、INSERT、UPDATE等命令也可以对ENUM和SET直接使用数字操作,如SELECT * FROM tbname WHERE colSET=65;

如果查询结果按ENUM和SET字段来排序,因为MySQL内部存储的实际是数字,所以排序结果是按照此字段的数字大小排序的,如果想把ENUM或SET字段按照字母表顺序排列,就必须明确的把它们转换为字符串形式,比如:SELECT CONCAT(x) AS xstr ... ORDER BY xstr。

DESC[RIBE] tablename //显示数据表的结构,等价于SHOW COLUMNS FROM tablename

DESC[RIBE] tablename columnname//显示数据表中的某个字段的结构。

其他的MySQL数据类型还有GEOMETRY, POINT(二维地理数据对象)等,后面会讲到。


 

1.5,定义字段时的选项和属性:

在创建字段的时候还可以定义许多属性。下表列出了最重要的选项。注意:许多属性仅适用于特定的数据类型。

mysql学习笔记_第7张图片

MySQL不允许使用函数来设置默认值。MySQL也不支持为数据列定义数据合法性检验规则,例如不可能值允许0~100之间的值存入某个数据列。


 

1.6,数据库设计技巧:

※数据库,数据表和数据列的名字最多可以是64个字符长。

※按照一定的规范给数据列起名有助于减少因粗心产生的错误,喜欢使用author_name这样的名字还是使用authorname这样的名字并不重要,关键是应该一直保持这种风格。

※类似的,还应该在选用单数名词还是复数名词作为名字的问题上做出统一的决定。本书作者在给数据表和数据列起名字的时候从不选用复数名词。这里并没有对错之分,但如果数据表里有一半名字是单数名词,另一半名字是复数名词,恐怕时间一长自己都会糊涂。

1.6.1,规范化

简单描述下三个范式(Normal Form标准型):

1NF: 字段属性不可再分

2NF: 要有主键

3NF: 消除冗余

数据库设计规范里有三个范式(normal form),自己总结一下就是:数据表尽可能细分,如果有字段的值出现重复,则需要为此字段单独创建一张表,然后创建一张表表示两张表的关联关系。计算机擅长处理数字类型,所以用数字对应起来的关系要比其他类型(如字符串)要有效率。

范式的优点:范式的优点是尽可能细分数据表,不会出现数据冗余。冗余意味着存储空间的浪费(但是对于现在的存储技术而言,存储空间的浪费往往不是什么大问题)。另外,严格按照范式设计出来的数据库能够提供最丰富最灵活的查询选项。

范式的缺点:数据表的个数越多,从中提取相关数据生成查询结果的复杂性也越大。为了提高查询的效率,适度的冗余有时反而是必要的。从多个数据表提取数据往往要比从单个数据表提取数据来得慢。(数据库的世界里有一个领域叫做“数据仓库”。在设计数据仓库的时候,人们往往会有意识的增加一些冗余度以获得更好的响应速度。不过MySQL数据库系统至少在目前还不是人们建设数据仓库时的首选。)

 


1.7,层次关系的处理(图书门类之间的层次)

P166。设计层次关系的数据表时,会出现同一张表的一个字段是另一个字段的外键。比如,图书类别的数据表中parentCatID是同一张表的字段catID的外键。catID是编程类书籍对应的编号,parentCatID是计算机类书籍对应的编号。

 

 


1.8,关系(两个数据表之间的关联/引用 关系)

两个数据表之间的关联/引用关系可以细分为以下3种:(理解1:n和n:m的关系对于实际设计数据表有很大帮助)

※1:1:在实际种很少见,因为两个有着1:1关系的数据表完全可以合并为一个。一个应用场景为:一个员工个人资料的数据表可以拆分为两个:一个是personnel数据表,用来存放需要经常查询和用不着保密的信息,另一个是personnel_extra数据表,用来存放不经常使用和需要保密的信息。如此可以通过限制无关人员对personnel_extra数据表进行访问就可以达到保护员工隐私又不影响日常工作的目的(但是这种谨慎在MySQL数据库系统里并不是很有必要,因为MySQL可以给数据表里的每个数据列分别设置一个不同的访问权限。而且从MySQL5.0开始,信息的保密问题还可以通过创建一些视图来解决)。拆分的第二个理由是提高了数据库系统的响应速度。但是缺点是系统会因为需要确保两个数据表里的数据保持同步而增加资源开销。

※1:n:1:n的关系时两个数据表之间最常见的关系,只要在第一个数据表(所谓'细节数据表')的数据记录里又一个特定字段引用了--无论是何种引用方式--第二个数据表(所谓‘主控数据表’)里的数据列,就会形成1:n的关系。

1:n的关系是通过键(key)字段发生的。主控表里的数据列由一个主键标识;细节表里则包含着一个外键字段,该字段的内容指向着主控表。比如,每家出版公司(1:n关系中的‘1')可以出版多本图书(1:n关系中的'n'):记录图书的数据表(细节数据表)中有一个字段指向记录出版公司的数据表(主控数据表)。

在创建数据库的时候,人们往往会有意识地给两个有着1:n关系的数据表里的响应数据列起上一个相同的名字,这种做法积分很有条理并有助于人们认清1:n的关系,但并不是必要的。

※n:m:第一个表里的一条记录对应第二个表里的多个记录,同时,第二个表里的一条记录也对应着第一个表里的多个记录。比如,订单和商品的关系。在比如图书和作者的关系。

n:m关系非常常见。在设计数据库的时候,需要为每两个有着n:m关系的数据表多定义一个辅助数据表,并利用这个辅助数据表把一组n:m关系转化为两组1:n关系。比如,书名信息数据表和作者信息数据表是n:m的关系,需要一个两个数据表之间联系的辅助数据表rel_title_author。注意,1:n是一张表里有一个字段记录另一张表里的信息,n:m理论上则是单独两张表内部没有任何交叉关系(当然可以为了查询效率做出一些冗余的交叉),所有的关系都是通过另一个独立的数据表联系的。

 


1.9, 主键和外键

1.9.1,主键

主键的任务是帮助MySQL以最快的速度把一条特定的数据记录在数据表里的位置确定下来(这种寻址操作发生的非常频繁)。

1.9.2,外键

1.9.2.1,外键的任务是引用另一个数据表里的某条记录,只不过这种引用关系是在构造数据库查询命令的时候而不是在声明数据表或数据列的时候定义的,比如下来SQL语句:SELECT col1,col1 FROM tb1,tb2 WHERE tb1.id=tb2.id;这条语句中的关键是WHERE tb1.id=tb2.id,正是它在数据表之间建立起了完成这个查询所必须的关系,其中一个id字段就是外键。

外键在数据表的定义声明里毫无特殊之处。在MySQL看来,外键不过是数据表里的有一个普通字段。在声明一个外键的时候,既不必使用特殊的保留字,也不必为它创建索引。不过有一点要注意:外键字段的数据类型应该尽可能与主键字段保持一致,否则WHERE条件的求解过程将非常慢。

1.9.2.2,引用一致性(又叫外键约束条件):注意,只对InnoDB类型的数据表有效

MySQL服务器将外键视为普通字段,而这会导致两个数据表的 数据 之间的关联/引用关系 遭到破坏。为了防止,MySQL提供了一种外键约束机制,该机制目前仅适用于InnoDB数据表。

1.9.2.2.1语法(外键约束条件可以理解为指针)

下面是为外键字段table1.column1设置外键约束条件的基本语法:

FOREIGN KEY [name] (column1) REFERENCES table2(column2)

[ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}]

[ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}]

说明:

①外键约束条件可以被命名为 name(可选,注意不能加单引号或双引号,可以加``)。被引用(参考)的一方是table2.column2字段,该字段必须配有索引(通常都是表的主键,但不是必须如此,只要是个键就可以了)。

②tb1.column1中不能插入或更新一个在tb2.column2中不存在的数据(引用一个不存在的数据不被允许); 如果没有ON DELETE 和 ON UPDATE,而且tb1.column1中已经存在某个数据,则tb2.column2则不能删除或更新此值(因为正在被引用着,当然那些没被引用的值是可以被删除的),而且,新版的MySQL中(5.6.17),无论tb1.column1中是否引用着tb2.column2的值,都不能对整个数据表tb2使用 truncate 或 drop命令(不知道能不能通过某个配置文件修改)

③有外键约束关系的两个字段的数据类型要尽可能一致(一些小的细节可以不一致,比如varchar(10) 与 varchar(11)等,但大的方面的属性必须要一致,否则外键约束关系会报错)。

④外键约束条件中的table1和table2允许是同一个数据表,此时,column1字段引用的将是同一个数据表里的column2字段。这将形成层次关系。

⑤ON DELETE子句是可选的,它定义了如果试图从table2数据表里删除一条被table1数据表引用的记录时,数据表驱动器该如何采取行动。

  ☆RESTRICT:这是默认行为。DELETE命令将引起一个错误,但那条记录不会被删除(DELETE命令引起了一个错误并不意味着正在执行的事务会半途而废,它只表明DELETE命令没有被执行而已。必须像往常一样用COMMIT或ROLLBACK命令来终止这个事务)。

  ☆SET NULL:table2数据表里的记录将被删除,table1数据表里受其影响的所有记录的column1字段将全部被设置为NULL。当然前提是table1.column1字段可以取值为NULL。

  ☆CASCADE:table2的记录将被删除,table1受其影响的记录同时被删除。

  ☆NO ACTION:table2里的记录将被删除,对table1数据表不采取任何行动。也就是说,引用一致性遭到破坏是可以忍受的。这个动作没有什么实用意义,因为它和没有定义外键约束条件时的情况是一样的。

1.9.2.2.2,设置外键约束条件的前提:

※其中一个或两个表是MyISAM类型的表,若要使用外键约束,必须都是InnoDB类型的表。

※数据列table1.column1和table2.column2都必须配有至少一个普通索引。新版都MySQL中的FOREIGN KEY 会自动创建一个索引。如果使用的是多字段索引(INDEX(columnA,columnB)),外键约束条件中的关键字字段必须出现在第一个 字段。否则,就必须为关键字字段再多创建一个索引。

数据类table1.column1 和 table2.column2的数据类型必须匹配到无需进行数据类型转换就可以直接进行比较的程度。最有效率的做法是把这两个字段都声明为INT或BIGINT类型-----注意,此时这两个数据列的正负符号类型必须相同(或者都是SIGNED,或者都是UNSIGNED)。另外注意两个数据列的字符编码也要一致。

※外键约束条件必须从一开始就要得到满足:如果数据表里已经有一些数据,开启可能会有个别记录不能满足外键约束条件的要求。此时要先修改那些记录。

1.9.2.2.3,删除外键约束条件

ALTER TABLE tablename DROP FOREIGN KEY foreign_key_id;

可以使用SHOW CREATE TABLE tablename命令查处需要删除的索引的foreign_key_id。注意,如果此时正使用着镜像功能,删除外键约束条件可能会引起问题。因为外键约束条件再镜像系统和原始系统上的名字可能不一样。

1.9.2.2.4,临时禁用外键约束条件 检查

SET foreign_key_checks=0 命令可以暂时关闭对外键约束条件的自动检查功能。有时,为了加快大数据表备份的读入速度,关闭这种检查还是必要的。SET foreign_key_checks=1命令可以重新启用这些规则。在这些规则被暂时禁用期间,不会检查对数据库的改动。如果在此期间有违反了这些规则的改动,因此二导致的错误将不会被自动纠正。

 


1.10,索引

1.10.1,为了在一个数据表里检索某个特定记录,或者提取一系列数据记录,MySQL必须把这个数据表里的所有数据记录都搜索一遍。如果数据表的体积比较庞大,查询时的性能就会显著下降。有个简单的办法可以交朋结友数据表性能下降的问题:为查询操作所涉及的数据列(比如,SELECT * FROM table WHERE column3=1234这条语句中的column3)创建并使用一个索引。

索引时一种特殊的文件(InnoDB数据表上的索引时表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针(数据库索引和一本书的索引有着同样的功能,不用把书从头到尾翻看一遍就能找到想要的内容,既省时间又省事)。

注意:索引并不是灵丹妙药!它们可以加快数据检索操作,但会使数据修改操作变慢。每修改一条数据记录,索引就必须刷新一次。为了弥补这一缺陷,许多SQL命令都有一个DELAY_KEY_WRITE选项。这个选项的作用是暂时制止MySQL在该命令每插入一条新记录和修改一条现有记录之后立即对索引进行刷新。索引的另一个明显缺陷是它们会在硬盘上占用相当大的空间,因此,应该职位最为经常查询和最经常排序的数据列建立索引。

MySQL把同一个数据表里的索引总数限制为16个。MySQL允许为多个字段的组合创建索引,这种索引对于涉及多个字的的查询/排序操作----如WHERE country='China' AND city='Beijing'-----特别有帮助。

1.10.2,InnoDB数据表的索引

与MyISAM数据表相比,索引对InnoDB数据表的重要性要大得多。在InnoDB数据表上,索引不仅会在搜索数据记录时发挥作用,还是数据行级锁定机制的基础。“数据行级锁定”的意思是在事务操作的执行过程中锁定正在被处理的个别记录,不让其他用户进行访问。这种锁定将影响到(但不限于)SELECT...LOCK IN SHARE MODE、SELECT...FOR UPDATE 命令以及INSERT、UPDATE和DELETE命令。

出于效率方面的考虑,InnoDB数据表的数据行级锁定机制实际发生在它们的索引上,而不是数据表上。显然,数据行级锁定机制只在有关的数据表有一个合适的索引可供锁定的时候才能发挥效力。

1.10.3,使用索引的限制

※如果WHERE子句的查询条件里有不等号(WHERE column!=/...),MySQL将无法使用索引。

※如果WHERE子句的查询条件里使用了函数,MySQL也将无法使用索引

※在JOIN操作中(需要从多个数据表提取数据时),MySQL只有在主键和外键的数据类型相同才能使用索引。

※如果WHERE子句的查询条件里使用了比较操作符LIKE 和 REGEXP,MySQL只有在搜索模板的第一个字符不是通配符的情况下才能使用索引。比如说,如果说查询条件是LIKE 'abc%',MySQL将使用索引;如果查询条件是LIKE ‘%abc',MySQL将不使用索引。

※在ORDER BY操作中,MySQL只有在排序条件不是一个查询条件表达式的情况下才使用索引(虽然如此,在涉及多个数据表的查询里,即使有索引可用,那些索引在加快ORDER  BY操作方面也没什么作用)。

※如果某个数据列里包含着许多重复的值,就算为它建立了索引也不会有很好的效果。比如说,如果某个数据列里包含的净是些诸如“0/1” 或 “Y/N”等值,就没有必要为它创建一个索引。

1.10.4,普通索引、唯一索引和主索引

※普通索引:普通索引(由关键字KEY 或 INDEX定义的索引)的唯一任务就是加快对数据的访问速度。因此,应该只为那些最经常出现在查询条件(WHERE column=...)或排序条件(ORDER BY column)中的数据列创建索引。只要有可能,就应该选择一个数据最齐整、最紧凑的数据列来创建索引(如一个证书类型的数据列)。

※唯一索引(Unique 索引):普通索引允许被索引的数据列包含重复的值。唯一索引可以保证数据记录的唯一性。

※主索引:主键字段必须要有一个索引,这个索引就是所谓的“主索引”。主索引和唯一索引的 唯一区别就是:前者在定义时使用的关键字是PRIMARY而不是UNIQUE。

※外键索引:如果为某个外键字段定义了一个外键约束条件,MySQL就会定义一个内部索引来帮助自己以最有效率的方式去管理和使用外键约束条件。

※符合索引:复合索引可以覆盖多个数据列,如INDEX(A,B,C); 一个知识点:复合索引INDEX(A,B,C)可以当作列A或列(A,B)的索引来使用,但不能当作列B或列C或列(B,C)的索引来使用。 

※索引的长度限制:在为CHAR和VARCHAR类型的数据列定义索引时,可以把索引的长度限制为一个给定的字符个数。这样可以生成一个尺寸较小,检索速度比较快的索引文件。在为BLOB和TEXT类型的数据列创建索引时,必须对索引的长度做出限制:MySQL所允许的最大索引长度是255个字符。语法例如:

ALTER TABLE tablename ADD INDEX/KEY (columnA(5));给columnA的前5个字符创建索引。

1.10.5,全文索引

文本字段上的普通索引只能加快对出现在字段内容最前面的字符串进行的检索操作。如果字段里存放了大段文字,普通索引就没什么用处了。这种检索往往以LIKE “%word%”的形式出现,这对MySQL来说很复杂,如果需要处理的数据量很大,相应时间就会很长。这类场合正是全文索引(full-text index)可以大显身手的 地方。在生成这种类型的索引时,MySQL将把在文本中出现的所有单词创建为一份清单,查询操作将根据这份清单去检索有关的数据记录。全文索引既可以随数据表一同创建,也可以使用如下命令追加:

ALTER TABLE tablename ADD FULLTEXT(column1,colulmn2)

有了全文索引,就可以用SELECT查询命令去检索那些包含着一个或多个给定单词的数据记录了。这类查询命令的基本语法为:

SELECT * FROM tablename WHERE MATCH(column1,column2) AGAINST('world1', 'word2', 'word3'); 

这条命令将把column1和column2字段里有word1、word2和word3的数据记录全部查找出来。(后面有全文索引的详解)

InnoDB类型的数据表在MySQL5.6之后才开始支持全文索引,之前只有MyISAM支持。

1.10.6, 查询和索引的优化

※只有当数据库里已经有足够多的测试数据时,它的性能测试结果才是有实际参考价值的。如果在测试数据库里只有几百条数据记录,它们往往会在第一条查询命令之后就被全部加载到内存里,这将使后续的查询命令都执行得非常快(不管有没有使用索引)。所以所以只有当数据库里的记录超过了1000条、数据总量也超过了MySQL服务器上的内存总量时,数据库的性能测试结果才有意义。

※在不确定应该在哪些数据列上创建索引的时候,可以从EXPLAIN SELECT命令那里获取一些帮助(即在普通的SELECT命令前加上关键字EXPLAIN),有了这个关键字,MySQL将不是去执行那条SELECT命令,而是去对它进行分析。EXPLAIN命令提供的信息很有用,但是想把它们看明白则必须具备一定的MySQL和数据库经验才行。

mysql学习笔记_第8张图片

 


1.11, 视图(View): MySQL5.0及以后的版本都可以使用视图

1.11.1, 视图可以为一个或多个数据表定义一个特殊的表现形式。视图在行为上与数据表没什么区别。视图还可以提供安全保障。如果一张数据表中一些数据是对所有人开放的,而另一些数据却是保密的,这时就可以把可以公开的那些数据创建为一个视图,然后通过设置MySQL访问权限让某些丧失只能访问这个视图,但不能访问这个视图背后的数据表。 

1.11.2, 视图相当于一个虚拟的数据表,创建视图的完整语法为:

CREATE [OR REPLACE] [ALGORITHM = UNDEFIINED | MERGE | TEMPTABLE] VIEW name [(columnlist)] AS select command [WITH [CASCADE | LOCAL] CHECK OPTION]

说明如下:

※CREATE VIEW...和 CREATE OR REPLACE VIEW....的区别和 DROP TABLE / DROP TABLE IF EXISTS的区别一样。

※[(columnlist)]是新的视图的字段名字,可以和原表不一样,但是个数要一样。

※WITH CHECK OPTION:此选项只有在视图允许刷新的时候才起作用(下面有讲什么时候视图可以被刷新)。如果带有此选项表示,只有当用来创建这个视图的SELECT命令的WHERE条件满足时才能允许对这个视图里的记录进行修改。

※WITH LOCAL CHECK OPTION和WITH CASCADE CHECK OPTION的含义:视图是可以从其他视图里派生而来,LOCAL的意思是只考虑本条CREATE VIEW命令的WHERE条件,不考虑父级视图的WHERE条件。而CASCADE则表示本视图以及所有父级视图的WHERE条件都必须考虑。如果没有给出CASCADE也没有给出LOCAL,则默认为CASCADE。

1.11.3, 在视图里修改数据记录

在视图里修改数据会将视图引用的基表中的数据也修改掉,而且此基表的其他视图也会更新!此处的修改包括:更新,删除,插入。换句话说,在基表和其产生的所有视图里,只要有一个地方改变了,其他地方都会改变!

能不能在某个视图里使用INSERT、UPDATE、和DELETE命令(或者说这个视图是不是可刷新的)要取决于当初用来创建这个视图的SELECT命令。可刷新的命令需要满足以下几个条件:

※当初用来定义视图的SELECT命令不得包含GROUP BY、DISTINCT、LIMIT、UNION或者HAVING等子命令。

※如果某个视图里的数据来自一个以上的数据表那么它几乎总是不可刷新的。

※视图应该包含主键索引、唯一索引、外键约束条件所涉及的全部数据列。如果视图里没有或缺少这样的数据列,就将由MySQL选项updatable_views_with_limit来决定是允许刷新并同时返回一条警告信息(默认设置)、还是不允许刷新并触发一个错误(设置为0)。

1.11.4, SHOW CREATE VIEW name

       DROP VIEW name;

   SHOW TABLES可以显示表和视图。


 

第二章,SQL语言入门

0,SQL语言即 Structured Query Language,结构化查询语言。

MySQL自带的命令解释器,即mysql程序在执行SQL命令的时候需要在末尾加个分号(也可用/g或/G代替分号,其中/g全等于分号,/G是另一种显示结果的方式)。但这不是MySQL的语法,其他的MySQL客户端程序都不要求这么做。

MySQL的数据库和数据表的名字是区分大小写的[后来验证了一下,在Linux下数据库和数据表的名字是区分的,但在windows下却是不区分的。不知道是不是可以通过配置一个变量控制这个],其他地方都不区分大小写。

 


1,SELECT

1.1,确定数据表里某个字段有多少条内容不重复的数据记录(DISTINCT)

SELECT COUNT(DISTINCT fieldname) FROM tbname;

SELECT DISTINCT field1, field2 FROM tbname; // 这里将筛选出field1和field2组合在一起不重复的数据记录。

☯---DISTINCT关键字的用法----⚽

  1,distinct只能用在select语句中。具体语法如下:select distinct expression[,expression...] from tables [where conditions];  expression可以是多个字段。

  2,多个字段时:select distinct id, name...【或者可以加上括号写为:select distinct(id, name)】表示id和name两个字段组合起来不同的记录。注意:distinct应用到多个字段的时候,其应用的范围是其后面的所有字段,而不只是紧挨着它的一个字段,而且distinct只能放到所有字段的前面,如下语句是错误的::select id, distinct name...

  3, distinct对NULL是不进行过滤的,即返回的结果中是包含NULL值的。

  4,与ALL不能同时使用。默认情况下select语句使用的其实就是all,只不过都被省略了。

  5,distinct关键字有一个同义词:distinctrow, 可以互相替代。

1.2, 限制查询结果中的数据记录个数(LIMIT)

※SELECT * FROM tbname LIMIT [n,]m;其中n代表偏移量(注意第一条数据的偏移量是0,偏移量可以省略),m代表需要显示的记录条数。注意LIMIT都是放在所有条件的最后。

※如果想知道使用了LIMIT的SELECT命令如果不使用LIMIT总共会返回多少条记录,除了专门使用COUNT()函数,还可以在使用LIMIT的SELECT语句中增加一个SQL_CALC_FOUND_ROWS选项,然后就可以在下一条查询命令里用SQL函数FOUOND_ROWS()查处这条SELECT命令在不带LIMIT关键字的情况下会返回多少条记录。用法如下:

SELECT SQL_CALC_FOUND_ROWS * FROM tbname LIMIT [n,]m;

SELECT FOUND_ROWS();两个命令是紧接着的。

1.3,对查询结果进行排序(ORDER BY)

ORDER BY fieldname [ASC | DESC ]

1.3.1,选择一种排序方式

在需要对字符串进行排序的时候,MySQL首先选用的将是人们在创建数据表时为有关数据列设置的排序(collate)方式;如果那个数据列上没有排序方式,MySQL将选用数据表上的排序方式;如果数据表上也没有排序方式,MySQL将选用数据库上的排序方式。如果数据库上也么有排序方式,MySQL将会反过头来选用那个数据列所使用的字符集的默认排序方式。(一个给定字符集的默认排序方式可以利用SQL命令:SHOW CHARACTER SET命令查看。)

如果想临时改用另外一种排序方式对查询结果进行排序(前提是字段使用的字符集有那种排序方式,可以使用SHOW COLLATION命令查看每种字符集可以使用的排序方式)。这种临时改用其他排序方式的做法将导致MySQL在排序时不适用任何索引。对于一个大数据表,临时该有其他排序方式将又慢又么有效率。

SELECT * FROM tbname ORDER BY fieldname COLLATE sortname.

如果给定的数据列上的可用排序方式里没有所需的,可以用CONVERT命令为这个数据列里的数据临时指定另外一种字符集。这将耗费大量的时间。

SELECT * FROM tbname ORDER BY CONVERT(field USING utf8) COLLATE utf8_polish_ci

1.4,筛选数据记录(WHERE, HAVING)

①SELECT authname FROM authors WHERE authname > 'M'// 查询出名字的第一个字母落在从"M" 到 "Z"区间内的图书作者的名字。

②SELECT authname FROM authors WHERE authname LIKE"%er%"//查询出名字里包含着字母序列er的作者。字符"%"是代表 任意字符串 的通配符。

③SELECT authname FROM authors WHERE authid IN (2,3,5) //枚举型查询

注意:MySQL不支持colname=NULL这样的用法-----如果打算对包含NULL值的数据记录进行搜索,就必须使用ISNULL(colname)函数。比如WHERE !ISNULL(colname)

查询条件还可以通过关键字HAVING来引导。如果HAVING和 WHERE同时出现,MySQL将优先执行WHERE子句,HAVING子句做进一步的筛选。对MySQL来说,HAVING子句不像WHERE条件子句那么容易优化,所以应该尽可能避免使用HAVING子句----除非找不到与之等价的WHERE子句。

关于关键词WHERE和HAVING的异同点

WHERE针对表中的列发挥作用,查询数据;HAVING针对查询结果中得到的列发挥作用(也就是说从查询出的结果集再次进行筛选),看下面两个例子:

SELECT colA AS a FROM tbname WHERE a > 100;这个SQL命令会报错,原因是a不是表中的列,如果把WHERE改为HAVING就可以。

UPDATE tbname SET colA='xx' HAVING colB=xx;这里就会报语法错误,因为colB是表中的列,不能用HAVING,只能用WHERE

1.5,涉及多个数据表的关联查询(LEFT / RIGHT JOIN)

假设有两个表tb1(a,b), tb2(a, c):

①SELECT b,c FROM tb1,tb2 //返回tb1记录数乘以tb2记录数

②SELECT b,c FROM tb1,tb2 WHERE tb1.a=tb2.a;

 SELECT b,c FROM tb1 [INNER] JOIN tb2 ON  tb1.a=tb2.a;

上面两条SQL语句的效果是一样的。

③SELECT b,c FROM tb1 LEFT [OUTER] JOIN tb2 ON tb1.a=tb2.a; // tb1是左表,tb2是右表,将以左表为基础为左表里的每一条记录生成一条结果记录,右表不符合条件的将生成NULL。

④SELECT b,c FROM tb1 LEFT [OUTER] JOIN tb2 USING(a);//效果和③一样,但是要求两个数据表里的关联字段是相同的名字,放在USING()函数中。

⑤SELECT b,c FROM tb1 NATURAL[LEFT [OUTER]] JOIN tb2;//效果也和③一样,自动使用两个数据表里名字相同的字段进行关联,即意味着两个数据表里除了一个相同的字段外不能再有任何名字相同的字段。没什么使用价值。

⑥SELECT b,c FROM tb1 RIGHT [OUTER] JOIN tb2 ON tb1.a=tb2.a;//tb1(依然)是左表,tb2是右表,将以右表为基础为右表里的每一条记录生成一条结果记录,左表不符合条件的将生成NULL。为了最大限度的和其他品牌的数据库系统保持兼容,最好不要使用RIGHT JOIN--应该把它改写为LEFT JOIN。上述⑥等价于如下的LEFT JOIN:SELECT b,c FROM tb2 LEFT JOIN tb1 ON tb1.a=tb2.a

⑦SELECT b,c FROM tb1 RIGHT [OUTER] JOIN tb2 USING(a);//同上,要求a是两个数据表里同名的关联字段。

另外,MySQL暂时不支持FULL JOIN(全连接),全连接返回的是LEFT JOIN和RIGHT JOIN的并集,但是可以用一些别的方法来实现全连接

 

https://www.cnblogs.com/bluedeblog/p/6654065.html   [JOIN关联表中ON,WHERE后面跟条件的区别]

数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。

在使用left jion时,on和where条件的区别如下:

1、 on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。on后接的条件作用是 为左表中的每条记录查询下右表,右表中有符合条件的就显示,没有就显示null

2、where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有left join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。

       假设有两张表:

表1:tab2

id
size
1
10
2
20
3
30

 

 

 

 


表2:tab2

size
name
 
10
AAA
20
BBB
20
CCC

 

 

 

 

 

 

两条SQL:
1、select * form tab1 left join tab2 on (tab1.size = tab2.size) where tab2.name=’AAA’
2、select * form tab1 left join tab2 on (tab1.size = tab2.size and tab2.name=’AAA’)

 

第一条SQL的过程:

1、中间表
on条件: 
tab1.size = tab2.size
tab1.id tab1.size tab2.size tab2.name
1
10
10
AAA
2
20
20
BBB
2
20
20
CCC
3
30
(null)
(null)
|
|

2、再对中间表过滤
where 条件:
tab2.name=’AAA’

tab1.id tab1.size tab2.size tab2.name
1
10
10
AAA
   

 

 

 

 

 

 

 

 

 

 

 

 

 

第二条SQL的过程:

1、中间表
on条件: 
tab1.size = tab2.size and tab2.name=’AAA’
(条件不为真也会返回左表中的记录)
tab1.id tab1.size tab2.size tab2.name
1
10
10
AAA
2
20
(null)
(null)
3
30
(null)
(null)

 

 

 

 

 

 

 

 

其实以上结果的关键原因就是left join,right join,full join的特殊性,不管on上的条件是否为真都会返回left或right表中的记录,full则具有left和right的特性的并集。 而inner jion没这个特殊性,则条件放在on中和where中,返回的结果集是相同的。

 

1.6,合并查询结果(UNION)

 从MySQL4.0开始,可以使用UNION关键字把多个SELECT查询命令合并在一起。语法如下:

SELECT command UNION [ALL] SELECT command ......

如果不加ALL,则重复的记录将从最终结果里被自动消除。使用了UNION ALL 则会把最终结果里的重复记录保留下来。

还可以把个别的SELECT命令用圆括号括起来,这样对每个SELECT命令都可以做出ORDER BY 和LIMIT设置。如:

(SELECT * FROM tb1 ORDER BY colA LIMIT 10)

UNION

(SELECT * FROM tb2 ORDER BY colA LIMIT 10)

ORDER BY colB LIMIT 5;

目前,UNION是MySQL里唯一的集合分隔符。MySQL没有提供关键字MINUS和INTERSECT,许多其他的数据库系统提供了这两个关键字。

1.7, 分组查询,统计函数(GROUP BY)

1.7.1, GROUP BY语法可以按一个给定的数据列的每个成员进行分组统计,最终看到的时一个分组汇总表。SQL语言提供的各种统计函数可以配合GROUP BY,可以在SELECT命令里用COUNT(),SUM(),MIN(),MAX()等函数。

1.7.2, 统计函数 GROUP_CONCAT()

统计函数GROUP_CONCAT()是从MySQL4.1版开始引入的,它的作用是把一些字符串归为一个分组。有点像编程语言中的把数组连接成字符串,比如某个字段查询结果有3条记录,对这个字段使用GROUP_CONCAT()则变为一条记录,此记录把原来的三条记录里的内容连接成了一个字符串。具体语法:

GROUP_CONCAT(fileld1[,field2,...] [ORDER BY colB SEPARATOR ';']) //最简单的直接把字段当作函数参数,具体点可以加上排序和自定义的分隔符 

1.7.3, 对多个数据列进行GROUP BY查询

GROUP BY也可以用来对多个数据列进行分组。即,GROUP BY colA,colB

1.7.4, GROUP BY ... WITH ROLLUP

从MySQL4.1开始,GROUP BY 又增加了一个新的关键字WITH ROLLUP(汇总)。①如果GROUP BY子句里只有一个数据列,加上WITH ROLLUP关键字的效果是MySQL将在查询结果的最后一行自动增加一条总数统计记录(SELECT中要有count()函数),这条记录的名字永远是NULL;②如果GROUP BY子句里有多个数据列,GROUP BY将为查询结果里的第一列分组(即GROUP BY后的第一个字段)统计一个阶段性总和(即第一个字段取某个值时,第二个字段遍历所有值的"小计")。最后再为全体记录统计一个最终的总和(“总计”)。

 


 

1.8, 备份数据

MySQL中备份数据可以有很多方法,除了mysqldump之类的专用工具,直接使用SQL命令也可以备份。

※为数据表制作一个副本

CREATE TABLE newtable SELECT * FROM table

此命令创建一个名为newtable的新数据表并把table数据表里的全部数据拷贝到这个新数据表里去。新数据表会丢失一些属性,如AUTO_INCREMENT,所有的索引等。这条命令可以更具体,比如:

CREATE TEMPORARY TABLE tb1 ENGINE=HEAP SELECT colA,colB,... FROM tb2 WHERE tb2.col=xxx;

为了避免这种方法中属性的丢失,更好的办法是先使用

CREATE TABLE newtable LIKE oldtable

命令创建一个与老数据表在结构上相同的新数据表,再用INSERT INTO ... SELECT...命令导入数据。

※用数据表副本恢复数据表

DELETE FROM table  或  TRUNCATE table // 将table里的现有记录全部删除

INSERT INTO table SELECT * FROM newtable

此命令把保存在newtable数据表里的数据全部插入到table数据表里去(在插入过程中,原始的AUTO_INCREMENT字段将得到恢复),注意确保数据列的个数、数据类型、先后顺序都准确无误。如果源数据表里的数据列个数比目标数据表里的少,可以在SELECT部分相应地给出几个NULL值或固定值,比如:SELECT NULL,publID,publName,ts,0,'abc'这样,经试验发现,如果目标数据库有个字段是AUTO_INCREMENT,恢复时给把NULL值传给这个字段,它会自动生成自增数字!很不错

恢复数据表的时候,如果目标数据表里本来有一些数据,那么容易出问题的地方是AUTO_INCREMENT字段:如果目标和源数据表里有ID编号相同的记录,INSERT命令就会报错(键重复),解决这个问题的办法有以下几个:

※可以使用INSERT IGNORE INTO...命令,插入时若有唯一键重复的记录,此条记录将不会被插入到目标数据表。

※可以用REPLACE ... 命令代替INSERT INTO...命令,如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据(此时显示2条记录受到影响,即原记录和新记录,实际表中只有一条记录变化了)。 2. 否则没有此行数据的话,直接插入新数据。(此时显示1条记录受到影响)。

※可以对唯一键字段做出一些调整,不让它们发生冲突。如下所示:publID是主键,tb1是目标数据表,tb2是源数据表

SELECT @maxid := MAX(publID) FROM  tb1;

INSERT INTO tb1 SELECT publID+@maxid FROM tb2

※为整个数据库制作一个备份

用mysqldump工具:mysqldump -uroot -p1234 dbname > backupfile

※用数据库备份文件恢复数据库

有两种方法,

①第一步:mysqladmin -uroot -p1234 create dbname  //先创建一个数据库

    第二步:mysql -uroot -p1234 dbname < backupfile //导入备份文件到数据库,这个命令不是进入mysql程序之后执行的,而是之前。

②第一步:先进入mysql里面,手动创建数据库:CREATE dbname.....  ; USE dbname;

 第二步:SOURCE backupfile; //最好不要出现中文路径,linux下backupfile文件的路径不能加引号


 

1.9, 插入数据记录(INSERT)

LAST_INSERT_ID()函数:此函数的唯一功能就是返回MySQL为上一条INSERT命令生成的AUTO_INCREMENT值。具体的使用细节如下:

转载自:http://blog.csdn.net/slvher/article/details/42298355

在使用MySQL时,若表中含自增字段(auto_increment类型),则向表中insert一条记录后,可以调用last_insert_id()来获得最近insert的那行记录的自增字段值(一个bigint类型的64-bit值)。

听起来似乎很简单易用,但事实上,使用last_insert_id()时有很多注意事项,否则很容易踩到坑。

本笔记的主要目的就是罗列这些需要引起注意的细节。

1. 向含auto_increment字段的表中正常插入一条记录后,last_insert_id()会返回表中自增字段的当前值。
这一点比较容易理解,这里不再展开。

2. 若在同一条insert语句中插入多行(如"insert into tbl_name (col_a, col_b) values ('aa', 'bb'), ('aaa', 'bbb')"这类SQL语句),则last_insert_id()返回的自增字段的"当前值"只在旧值的基础上加1,这与实际情况不符(表中的实际情况是自增字段值在旧值基础上加N)!感兴趣的话,可以建张测试表亲自验证这一点。

3. 假设用形如"INSERT ... ON DUPLICATE KEY UPDATE"的SQL语句更新表,此时,若该语句的实际作用是insert操作时,调用last_insert_id()会返回本次insert后自增字段的当前值;而若该语句的实际作用是update操作时,调用last_insert_id()返回的是自增字段的旧值,而非当前更新行的自增字段值,所以这个值无意义(因为调用last_insert_id()是想获取sql影响到的行的自增字段值进而做其它逻辑业务的,如果得到的值并非sql操作影响到的行对应的自增值,则这个值对业务来说无意义),按照MySQL手册的说明,若业务开发者想得到实际update操作影响到的行的自增值,可以用形如"INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;"的SQL语句来获取。
关于带参数的last_insert_id()函数的使用说明,可以参考本文第8条的说明。

4. 若在SQL中显式指定自增字段的值,如假设某张表由两列(id, name)构成,其中id为自增类型,假设当前表中id值为2,那么,执行"insert into test_tbl (id, name) values (11, 'test3');"后,再执行"select last_insert_id()",可以发现,得到的结果依旧是2。也即,只有自增字段由mysql来分配时,last_insert_id()才可能得到正确的值;SQL中显式更新自增字段值时,last_insert_id()返回的值不可用!

5. 如果sql语句执行出错,则调用last_insert_id()的值未定义。例如,若事务因执行出错回滚,则last_insert_id()的值不会恢复到事务执行前的那个值。

6. last_insert_id()的值是由MySQL server来维护的,而且是为每条连接维护独立的值,也即,某条连接调用last_insert_id()获取到的值是这条连接最近一次insert操作执行后的自增值,该值不会被其它连接的sql语句所影响。这个行为保证了不同的连接能正确地获取到它最近一次insert sql执行所插入的行的自增值,也就是说,last_insert_id()的值不需要通过加锁或事务机制来保证其在多连接场景下的正确性。

7. 如果通过"insert ignore"语句尝试插入新纪录,假设由于unique key冲突导致插入不成功,则auto_increment计数器不会变化,根据MySQL手册的说明,此时调用last_insert_id()会返回0表示没有新行被插入。但我在MySQL 5.1.73版本上测试的结果显示,last_insert_id()只是维持旧值而已,并不会返回0。

8. last_insert_id(expr)的行为
若调用last_insert_id()时传入了参数,则它会将参数值返回给调用者,并记住这个值,下次调用不带参数的last_insert_id()时,仍会返回这个值。可以利用这个特性实现一个多用户安全的全局计数器,示例如下:
1) 先创建一张表

  1. mysql> CREATE TABLE sequence (id INT NOT NULL);  
  2. mysql> INSERT INTO sequence VALUES (0);  

2) 每条连接执行下面的SQL语句来获取为其自动分配的全局唯一ID

  1. mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);  
  2. mysql> SELECT LAST_INSERT_ID();  

当然,上面给出的全局ID分配器只是一种思路,在实际工程实现中,频繁的update操作可能会造成系统瓶颈,可以参考PERCONA MYSQL PERFORMANCE BLOG这篇文章的优化思路(比如MySQL前面用cache抗read压力,通过delay update来减缓update压力)。

【参考资料】
1. Mysql Reference Manual: Function LAST_INSERT_ID
2. PERCONA MYSQL PERFORMANCE BLOG

================== EOF ================

 


1.10, 修改数据记录(UPDATE)

※更新排序清单里的数据记录(UPDATE...ORDER BY...LIMIT):

如果指向对满足某种排序条件的前n条或后n条数据记录进行修改,可以给UPDATE命令加上必要的ORDER BY 和LIMIT 子句(MySQL4.0及更高版本)。如,

UPDATE tablename SET mydata=xxx ORDER BY name LIMIT 10;

※更新关联数据表里的数据记录

UPDATE tb1,tb2 SET tb1.colA=tb2.colB WHERE tb1.ID=tb2.ID//此命令将对数据表tb1里的一些数据记录的colA字段做出修改,新数据来自tb2.colB数据列,这两个字段之间的关系通过两个数据表里的字段ID建立。

 


 

1.11, 删除数据记录(DELETE)

MySQL没有提供任何可以提供用来回复被删除记录的“撤销”机制。

※删除关联数据表里的数据记录

从MySQL4.0开始,DELETE命令新增了如下语法:

DELETE t1,t2 FROM t1,t2,t3 WHERE condition1 AND condition2...

这条命令将把数据表t1和t2里满足WHERE条件的所有数据记录全部删除,而WHERE条件可以是数据表t1,t2和t3之间的任何关联/引用关系。简单的说就是,DELETE命令将只从FROM之前的数据表里删除数据记录,但在WHERE条件里允许使用任何一个出现在关键字FROM之后的数据表的名字。

注意,删除关联数据表里的数据记录时,如果遇到外键约束条件限制的错误提示,可以先通过SQL命令:SET foreign_key_checks=0命令暂时的关闭MySQL的外键约束条件检查机制,等执行完DELETE命令之后再用:SET foreign_key_checks=1命令重新启用该功能。

※删除排序清单里的数据记录(DELETE ....ORDER BY .... LIMIT )

DELETE FROM tbname ORDER BY colA DESC LIMIT 3;

※多表连接删除

原地址为: https://blog.csdn.net/scholar_man/article/details/46842823

举例如下:现在有两个表t1, t2。

1,删除数据表t1中的相关记录,这些记录在t2中存在。

DELETE  t1  FROM  t1,t2  WHERE t1.id = t2.id; 

 这个语句等同于:

DELETE FROM t1  USING t1,t2   WHERE t1.id = t2.id;

2,删除t1中的相关记录,这些记录在t2中 不存在。

DELETE t1  FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.id IS NULL;

这个语句等同于:

DELETE FROM t1 USING t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.id IS NULL;

 

这个需求还有另外一种SQL实现方法,但是有的版本可以,有的版本不可以,了解一下:

delete from t1 where not exists (select 1 from t2 where t1.id = t2.id).

虽然有些版本删不掉,但是都是可以查出来的。

select * from t1 where not exists (select 1 from t2 where t1.id = t2.id);

 

3,找出两个表中相同记录的数据,并把两个表中的数据都删除掉。

DELETE t1,t2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t1.id = 1;

用别名的方式如下:

DELETE a,b FROM t1 a LEFT JOIN t2 b ON a.id = b.id WHERE a.id = 1;

如果使用了别名,那么其他所有地方都要用别名,否则会报错。如以下两种情况会报错:

delete t1,t2 

from t1as a

left join t2as b

on a.id=b.id

where a.id=5

***********************

DELETE a,b

FROM t1 a

LEFT JOIN t2 b

ON a.id=b.id

WHERE t1.id=2

所以,如果使用了别名的方式,那么上下一致都用别名。


 


 


2,创建数据表、数据库和索引

 


2.1,创建数据库(CREATE DATABASE)

创建数据库的操作将在硬盘上创建出一个子目录来。

CREATE DATABASE dbname [DEFAULT CHARACTER SET utf8 COLLATE utf8_bin]

 


2.2, 创建数据表(CREATE TABLE)

CREATE  [TEMPORARY] TABLE [IF NOT EXISTS] tbname()[ENGINE=MyISAM | InnoDB | HEAP DEFAULT CHARSET=csname COLLATE=collatename COMMENT='表的注释']

 关于TEMPORARY TABLE和普通的TABLE有什么区别,请阅读: https://yq.aliyun.com/articles/42028 

自己简单总结下:①临时表在本次连接断开后就会被自动清除,下次再进来就没有了;②在同一个连接(session)下,临时表和普通表的名字可以相同,而且无论建表的顺序如何,临时表的优先级总是高于普通表,所以同名的两个表在操作时总是先操作临时表。


 

2.3, 创建索引(CREATE INDEX)

有3种方法可以创建索引:①随数据表一同创建②使用CREATE INDEX③使用ALTER TABLE。3种方法效果完全一样,例如:为title字段创建名为indextitle索引。

①CREATE TABLE tbname(title ......, INDEX indextitle (title))

②CREATE INDEX indextitle ON tbname (title)

③ALTER TABLE tbname ADD INDEX indextitle (title)

※如果想只对字段的(比如说)前10个字符而不是全部字符进行索引,可以使用如下方法:

CREATE INDEX indextitle ON tbname (title(10))

※SHOW INDEX FROM tbname命令可以生成一份现有索引的名单。

※DROP INDEX indexname ON tbname命令可以删除指定的索引。

 


2.4, 更改数据表的结构(ALTER TABLE)

ALTER TABLE最重要的一些变体如下:

※ 增加一个数据列

ALTER TABLE tbname ADD newcolname ... [FIRST | AFTER existingcolumn]

※修改一个数据列

ALTER TABLE tbname CHANGE oldcolname new colname ...//CHANGE可以改写字段的名称,而且新旧名称必须都写。

ALTER TABLE tbname MODIFY oldcolname ....//modify只修改字段属性,不修改字段名字

※删除一个数据列

ALTER TABLE tbname DROP colname

※增加一个索引

ALTER TABLE tbname ADD PRIMARY KEY (indexcols)

ALTER TABLE tbname ADD INDEX [indexname] (indexcols)

ALTER TABLE tbname ADD UNIQUE [indexname] (indexcols)

ALTER TABLE tbname ADD FULLTEXT [indexname] (indexcols)

※增加一个外键约束条件

ALTER TABLE tb1 ADD FOREIGN KEY [indexname](colA) REFERENCES tb2 (colB)

※删除一个索引

ALTER TABLE tbname DROP PRIMARY KEY

ALTER TABLE tbname DROP INDEX indexname

ALTER TABLE tbname DROP FOREIGN KEY indexname //注意这里的indexname是外键约束条件的名字,而不是外键字段的索引名。例如,CONSTRAINT `matches_ibfk_1` FOREIGN KEY (`goaler`) REFERENCES `players` (`name`)中的 `matches_ibfk_1` 

※改变全体文本数据列上的字符集和排序方式

ALTER TABLE tbname CONVERT TO CHARACTER SET charsetname COLLATE collatename //注意,这个命令会将所有文本字段以及整个数据表的默认字符集和排序方式变为指定值

注意对比这个SQL命令:ALTER TABLE tbname [DEFAULT] CHARACTER SET charsetname COLLATE collatename //这个命令只会改变表的默认字符集和排序方式,表里的文本字段的字符集和校验方式保持不变

※改变数据表的类型(MyISAM、InnoDB)

ALTER TABLE tbname ENGINE typename //同理可以改变数据表的字符集和校验方式以及表的注释等。

如果需要对大量的数据表进行类型转换,UNIX/Linux环境下的mysql_convert_table_format脚本很值得选用。-? /--help显示使用方法。

 


 

2.5, 删除数据库和数据表(DROP)

删除是不可逆的:

DROP TABLE [IF EXISTS] tbname1,tbname2... // 删除数据表

DROP DATABASE [IF EXISTS] dbname1,dbname2.... //删除数据库

 


2.6, SHOW 命令

 

※人们把不是关于数据表里的内容而是关于数据表自身属性的信息称为元数据(metadata).关于meta(元)一词的解释如下:

META是一种思想概念,一种抽象思维,用来描述数据的数据,比如有一张学生表,记录着学生的基本信息,我们通过表可以获取学生信息(数据),但是有时候也要得到表本身的信息数据(比如表结构信息:字段名称,字段数据类型,长度等信息),对于这种基础信息的描述,就会使用META的概念,使用META元数据来描述表本身。放到HTML中也是一样的,HTML用来描述网页信息,但是HTML自己也有一些信息(比如网页标题,网页描述,搜索关键字),这些信息也就称之为HTML META信息,并且HTML也定义了专门的META标签。

所以,MySQL是研究(存储)数据的,那么MySQL自身的一些数据(比如,有哪些数据库,有哪些数据表,数据表中有哪些数据列,数据列的属性等等都是)就是元数据了。 

※查看元数据的传统办法是指向相应的SHOW命令,如SHOW DATABASES将会返回一份当前用户可以访问的全体数据库的清单。下面汇总了用来查看数据库和数据表元数据的命令,这些命令中的大多数都可以使用LIKE pattern选项对其返回结果做出筛选,比如SHOW DATABASES LIKE 'test%'只显示名字以test开头的数据库。

SHOW DATABASES

SHOW TABLES [FROM dbname]

SHOW [FULL] COLUMNS FROM tbname //不带FULL的这条命令和DESC tbname效果一样。

SHOW INDEX FROM tbname

 


2.7, INFORMATION_SCHEMA数据表家族

虽然SHOW命令对人们有很大帮助,但是它们不符合SQL:2003标准。从MySQL5.0开始,引入了一批INFORMATION_SCHEMA数据表,可以使用SELECT命令从这些数据表里检索关于数据库/表/列 等元数据。对这些数据表查询返回的信息比SHOW命令丰富的多。

INFORMATION_SCHMMA是一个虚拟数据库而不是一个真实存在的文件。其中的数据表不允许修改(只能使用SELECT命令查询)。其中的数据表和数据列的名字都符合SQL:2003标准中的规定。其中的数据表对全体MySQL用户开放,各用户的MysQL访问权限对它们没有效力。

下表列出了INFORMATION_SCHMEA中的部分数据表表示的信息:

mysql学习笔记_第9张图片

 

 


第三章,SQL解决方案(第二章的延续)

 1, 字符串

1.1,基本函数(介绍部分,汇总在第五部分第一章SQL语法指南)

1.1.1,合并字符串

CONCAT(s1,s2,...)

1.1.2,截取字符串

SUBSTRING(str, start[, length]):返回值是给定字符串str从位置start(注意,第一个字符的位置是1而不是0)开始算起的length个字符,length若省略则表示截取到最后。如果start是负值,则最后一个字符是-1,往前依次是-2,-3,...

LEFT(str, length): 相当于SUBSTRING(str, 1, length)

RIGHT(str, length): 相当于SUBSTRING(str,-length,length)

MID(str, start, [length]): 和SUBSTRING()函数一样。

1.1.3,确定字符串的长度

CHAR_LENGTH(str):返回值是字符串中的字符个数

LENGTH(str): 返回值是字符串的字节长度值

1.1.4,其他

IF(a,b,c): 此函数先对条件表达式a求值,如果结果为真(TRUE),则返回b;否则返回c。

REPLACE(str, search, replacement): 将字符串str中的子字符串search全部替换为字符串replacement。

LOCATE(search, str): 返回子字符串search在字符串str中的位置(只返回第一次出现的位置),字符串的第一个位置是1,所以如果返回值为0,表示字符串str中没有search。


1.2,改变字符集

1.2.1, 可以用CONVERT(x USING charset)函数来改变给定字符串的字符集。如,

SELECT CONVERT(colA USING utf8) FROM tbname;

如果想看到CONVERT()函数的调用结果,可以先把字符串转换为十六进制形式(使用HEX()函数)再显示:

SELECT HEX(CONVERT(...));

1.2.2, 指定某个字符串的字符集(投射操作符)

在默认的情况下,通过MySQL客户端程序(如,mysql程序,phpMyAdmin,PHP脚本等)输入的字符都将使用客户端的默认字符集。如果需要在SQL命令里使用另一种字符集的字符或字符串,就必须给它们加上一个投射操作符作为前缀以指定它们的字符集设置。这种投射操作符由一个下划线字符和那个临时字符集的名字构成(如_uft8或_latin1):

UPDATE tbname SET colA=_uf8 'xxx' WHERE cond;

1.3, 设置客户端字符集

在MySQL服务器上,不同的数据库、数据表、甚至是数据列可以使用不同的字符集,但绝大多数MySQL客户端(如PHP脚本、MySQL命令解释器mysql程序等)都不具备这种同时支持多种字符集的能力,每次只能使用一种字符集。MySQL客户软件库可以把从客户端发往服务器和从服务器返回客户端的字符串自动转换为相应的字符集编码,如果在转换时遇到了无法标识的字符,该字符将被替换为一个问号("?")。

客户端和服务器之间的字符集转换工作由几个MySQL系统变量控制,如下表:

mysql学习笔记_第10张图片

可以使用SHOW VARIABLES LIKE 'character_set_%'查看这些系统变量的值。

如果想处理UTF-8数据,需要发出一下命令(三个都表示设置当前会话的变量值):

SET @@session.character_set_client    =     'utf8'

SET @@character_set_results  =    'uf8'

SET character_ set_connection  =   'uf8'

上面三条命令和SET NAMES 'utf8'的效果一样,它一次就可以把3个变量都设置好。

另外还有一个办法:SET CHARACTER SET ‘utf8'命令,他将把character_set_client和character_set_reslut变量设置为utf8,在把character_set_database变量的值传递给character_set_connection变量。

设置完毕后,在SQL命令里输入的字符串将默认使用UTF-8字符集,SELECT查询结果里的字符串也将默认使用UTF-8字符集。


 

1.4, 模板匹配

1.4.1, 用LIKE操作符进行模板匹配

LIKE操作符适合完成简单的模板匹配任务,它支持两个通配符:下划线(_),匹配单个字符;百分号字符(%),匹配多个(包括0个)字符。和普通的字符串比较操作一样(比如:’B' > 'a'表达式为真,'a'>'A'表达式为假),LIKE操作符也不区分大小写。如:

SELECT 'MySQL‘ LIKE ’%sql'; 将返回1,即'MySQL‘ LIKE ’%sql'这个表达式为真,结果为1.

SELECT 'MySQLs' LIKE '%sql'; 这个表达式返回0, 因为‘%sql’表示结尾是sql(不区分大小写)三个字符的任意字符串。

如果字符"_"或“%”本身需要出现在匹配模板里,必须在它们的前面加上一个反斜线字符(\)进行转义,如:“50%” LIKE “%\%”(此表达式结果为1)。如果想用另外一个字符代替反斜线作为转义引导字符,可以使用以下语法:SELECT '50%' LIKE '%#%' ESCAPE '#'(这个表达式的结果也为1,escape这个单词在计算机中意思就是转义)。

1.4.2, 用REGEXP操作符进行模板匹配

REGEXP操作符(以及它的同义操作符RLIKE)可以构造更加强大的匹配模板(这是正则匹配模板!)。与LIKE操作符一样,REGEXP操作符也不区分大小写。如:

SELECT ‘abcabc' REGEXP 'Abc'//结果返回1,只要字符串中出现abc(不区分大小写)就返回1。正则里的规则这里都适用,^表示开头$表示结尾等等。

MySQL中的正则模式不支持大小写形式,如果想区分出大小写,就需要让字段本身能够区分出大小写,如①collate utf8_bin的字段就能区分出大小写②二进制字符串xxxBLOB等能区分出大小写③给字符串加上BINARY属性之后也能区分出大小写(BINARY是个投射操作符,其作用是改变一个操作数的数据类型,具体效果是把一个数字或一个字符串转换为一个二进制对象)。例如:

SELECT BINARY 'abcabc' REGEXP 'Abc';//结果将返回0,区分了大小写。

模板匹配操作在比较大的数据表上执行的非常慢,在许多场合,用一个全文检索操作来代替模板匹配操作会更有效率。

 


2, 日期和时间

 


 


2.1, SQL命令里的日期和时间必须以MySQL服务器能够接受的字符串格式给出。以下三个查询是等效的,对DATETIME 和 TIMESTAME 数据列都适用。

SELECT * FROM tbname WHERE ts BETWEEN '2011-11-11 11:11:11' AND '2022-11-11 11:11:11'; ts表示一个时间字段

SELECT * FROM tbname WHERE ts BETWEEN '2011/01/11 11:11:03' AND '2022/11/11 11:11:11';

SELECT * FROM tbname WHERE ts BETWEEN '20111101111101' AND '20221111111111';

BETWEEEN a AND b中的a和b都包括在范围之内。闭区间。

 


2.2,按年、月、日进行分组查询,下面的ts表示一个timestamp或datetime类型的字段名称。

YEAR(ts): 返回时间字符串中ts中的年份;

MONTH(ts): 返回时间字符串ts中的月份;

DATE_FORMAT(ts, "%Y-%m"):设置时间的输出格式,此函数详情见后面第五部分第一章

例一:从数据库中查询出2017年里各个月份的记录个数

SELECT MONTH(ts) AS m,COUNT(*) FROM tbname WHERE YEAR(ts)=2017 GROUP BY m;

例二:从数据库中查询出各个年份各个月份的记录个数

SELECT DATE_FORMAT(ts, "%Y-%m") AS m_y, COUNT(*) FROM tbname GROUP BY m_y;


2.3, 与日期和时间有关的计算

 mysql学习笔记_第11张图片

mysql学习笔记_第12张图片

mysql学习笔记_第13张图片


2.4, UNIX时间戳

UNIX操作系统以1970年1月1日00:00:00(这是格林威治时间,在东八区则是1970/01/01 08:00:00,也就是说时间戳是受时区影响的)作为系统时间的起点。从那时起每过一秒,UNIX的系统时间计数器就递加一个1,由此得到的整数被称为“UNIX时间戳”。

UNIX时间戳与MySQL中的TIMESTAMP时间值完全是两回事。MySQL在存储一个时间值时使用的内部数据格式与UNIX类似,但在执行SQL命令的时候会把时间值转换为"2017-12-31 23:59:59"这样的字符串。

UNIX时间戳在存储时其实就是一个整数,因为历史的原因,这个整数是一个32位整数。如此算来,这个整数将在2038年的某一天出现溢出。未来怎么办呢?首先,如果把UNIX时间戳看做是一个无符号整数的话,它还有一个符号位可用,这意味着它发生溢出的时间将推后到22世纪初。更有可能的是UNIX/Linux操作系统在最近几年就会使用一个64位的整数来存放时间戳数值,而这意味着在2038年极有可能不会再发生“千年虫”事件(YEAR 2000)。

2.4.1, 转换函数

FROM_UNIXTIME(): 接收一个时间戳参数,将其转换为"2017-12-31 23:59:59"字符串格式

UNIX_TIMESTAMP():接收一个日子字符串,将其转换为UNIX时间戳;

NOW(): 无参数,返回当前的时间,和常量CURRENT_TIMESTAMP的返回值一样。

 


2.5, 地理时区

MySQL在存储TIMESTAMP值时使用的是UTC(Coordinated Universal Time,全球协调时间),但在执行SQL命令时会把TIMESTAMP值转换为本地时区里的时间值。

2.5.1,服务器时区和客户端时区

※服务器时区(系统变量global.time_zone)

查看MySQL服务器正在使用的时区:

SELECT @@global.time_zone

上面查询结果通常是system,意思是MySQL服务器使用的是主机上的时区设置,可以使用

SELECT @@global.system_time_zone //查看主机正在使用的时区。

例子:使用函数NOW()和系统变量UTC_TIMESTAMP计算本地系统时间和UTC时间之间的地理时差:

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP) // 08:00:00

拥有SUPER权限的MysQL用户可以随时使用

SET @@global.time_zone=...

命令改变MySQL服务器的时区设置,这么做的前提是MySQL服务器没有启用二进制日志机制或镜像(动态备份)机制。如果其中任意一个被启用,就只能通过先修改MySQL配置文件 (/etc/mysql/my.cnf 或 my.ini)里的default-time-zone选项,再重新启动MySQL服务器的办法去改变MySQL服务器的时区设置。

关于时区的取值如下所述:

□Windows: 如果MySQL服务器运行在Windows环境下,就只能以UTC格式来设置系统时区,比如说,“+1:00”是柏林、"+0:00"是伦敦、"-5:00"是纽约、"+8:00"是北京等

□Linux:如果MySQL服务器运行在UNIX/Linux环境下并经过了适当的配置(后面的章节会讲到),就可以使用操作系统的时区名来设置MySQL服务器的时区。比如说,"European/Berlin"或"CET"是柏林、"European/London"或"Greenwich"是巴黎、"America/New_York"是纽约等。当然也可以使用UTC格式。

※客户端时区(系统变量session.time_zone)

查看客户端正在使用的时区:

SELECT @@session.time_zone

默认情况下,MySQL客户端会直接使用MySQL服务器的时区设置。如果需要改变客户端的时区设置,可以使用SET [@@session.]time_zone=...,当MySQL客户端和MySQL服务器之间的连接断开后,客户端时区的设置值将会丢失。

2.5.2,调整时区影响到的MySQL数据类型和函数

2.5.3, 不同时区的手工转换

不管MySQL客户端和服务器的时区设置如何,都可以用CONVERT_TZ(datetime, from_timezone, to_timezone)函数来转换不同时区的时间。第一个参数是一个时间值(如期加时间,只给出时间是不行的),第二个参数是第一个参数所在的时区,第三个参数是准备转换过去的时区。如,将东八区时间转为伦敦时间

SELECT CONVERT_TZ('2017-1-11 13:22:23','+8:00','+0:00'); //2017-01-11 05:22:23 


3,变量与条件表达式(IF 、CASE)

3.1,变量

MySQL里的变量可以分为3大类:

※普通变量。这类变量的标志是以字符@开头,它们在SQL连接被关闭时将失去内容。

※系统变量和服务器变量。这类变量的内容是MySQL服务器的工作状态或属性,它们的标志是以两个@@字符开头,许多系统变量都有两种形式,一个对应着当前连接(如,@@session.wait_timeout),另一个对应着整个MySQL服务器(如,@@global.wait_timeout,它包含着这个变量的默认值),"@@直接+变量" 首先是session的,没有session的就是global的;

※存储过程里的局部变量。这些变量是在存储过程(MySQL5.0新增功能)内声明的,只在存储过程内有效。没有统一的特殊标志,但变量名必须和数据表和数据列的名字有区别。

本节主要讨论普通变量,其他两类后面章节专门讲。

3.1.1, 变量的赋值

变量的赋值有下面好几种方法:

SET @varname = 3

SELECT @varname := 3

SELECT @varname := COUNT(*) FROM table //如果查询结果有多条,变量被赋值最后一条的内容,变量只应对应一个字段。

SELECT COUNT(*) FROM table INTO @varname //查询结果只能有一行记录且一个字段

SELECT colA,colB FROM table WHERE ... INTO @var1,@var2//查询结果只能有一行记录,且前面的字段数和后面的变量数目要一致。

3.1.2,, 变量的使用

实际工作中,用SQL语言来完成计算的情况非常少见,对于比较复杂的查询或插入操作,使用PHP或Perl语言来编程更方便,这样就用不着使用MySQL变量了。

 


3.2,条件表达式

3.2.1,IF查询

IF(condition, result1, result2)

INULL(expr):如果是exprNULL值,则返回1,否则返回0.

IF(ISNULL(expr1),expr2, expr1)等价于下面的IFNULL函数

IFNULL(expr1, expr2): 如果expr1的值是NULL,则返回expr2,否则返回expr1。

3.2.2,CASE分支

CASE结构有两种语法变体。

①,CASE expr

    WHEN val1 THEN result1

    WHEN val2 THEN result2

       ...

    ELSE result n

  END

②,CASE

    WHEN cond1 THEN result1

    WHEN cond2 THEN result2

    ...

    ELSE resultn

    END

一个例子:生成一份按其名称排序的图书清单,但是排序的时候不让a、an、the参加排序。即A Programmer's book将会被排在字幕P下而不是A下,SQL命令如下:

SELECT title FROM titles ORDER BY

CASE

  WHEN LEFT(title,2)='a ' TEHN SUBSTRING(title, 3)

  WHEN LEFT(title,3)='an ' THEN MID(title, 4)

  WHEN SUBSTRING(title, 1, 4)='then ' THEN MID(title, 5)

  ELSE title

END;

注解:像这样的搜索条件会让SQL查询变得非常慢:MySQL将不得不先创建一份所有图书的清单再进行排序,title数据列上的现有索引全都帮不上忙。


3.2.3,统计报表(Pivot Tables,有时也译为透视表)

许多数据库系统特工特殊的OLAP(online analytical processing,实时分析处理)命令来创建统计表格,OLAP包括了特殊的方法来管理和处理多维数据(多维的意思时多种不同的特征,数据就是按照这些特征被分组的)。具备OLAP能力的数据库系统经常被人们称为数据仓库(data warehouse)。

可以的是MySQL不支持OLAP函数,除了GROUP BY。对于比较简单的统计问题,可以利用MySQL中的SQL函数来解决。非常实用的是SUM()和IF()函数的组合,下面举几个例子:

例一:统计出每一种类的图书 的 不同语言各有多少本

SELECT catName,

SUM(IF(titles.langid=1, 1, 0)) AS english,

SUM(IF(titles.langid=2, 1, 0)) AS deutsch,

SUM(IF(titles.langid=3, 1, 0)) AS svensk,

SUM(IF(titles.langid=4, 1, 0)) AS norsk,

COUNT(*)

FROM titles, categories, languages WHERE titles.catid=categories.catid AND titles.langid=languages.langid

GROUP BY catName WITH ROLLUP.

显示结果如下:

mysql学习笔记_第14张图片

 这条查询命令里有个明显的弊端:如果语言有30种,那么SUM()也要有30个,为了解决这个问题,需要借助脚本语言为这个查询编写一段SQL代码:先获得一份所有语言的清单,再为每种语言构造出一个SUM()函数,最后把它们合并为一个完整的查询命令。

例二:月度查询统计报表(原理和例一一样)

一个数据表votelanguage,有三个字段,其中choice取值为1~6,分别代表一种编程语言,查询其中一条记录如下:

mysql学习笔记_第15张图片

现在要求查询出每年的每个月份 的各个编程语言占当月的百分比。ROUND(3.235, 2)//3.24,函数用于取近似值。SQL命令如下:

SELECT DATE_FORMAT(ts, "%Y-%m") AS month, 

ROUND( SUM(IF(choice=1, 1, 0)) * 100 / count(*), 1) AS c,

ROUND( SUM(IF(choice=2, 1, 0)) * 100 / count(*), 1) AS Java,

ROUND( SUM(IF(choice=3, 1, 0)) * 100 / count(*), 1) AS Perl,

ROUND( SUM(IF(choice=4, 1, 0)) * 100 / count(*), 1) AS PHP,

ROUND( SUM(IF(choice=5, 1, 0)) * 100 / count(*), 1) AS VB,

ROUND( SUM(IF(choice=6, 1, 0)) * 100 / count(*), 1) AS Other,

COUNT(*)

FROM votelanguage GROUP BY month  WITH ROLLUP;


4,子查询(Subquery, 从MySQL4.1版本开始支持)【无论在任何地方使用子查询,都必须用括号()括起来】

【新增】关于in和find_in_set()的子查询说明:

1, select * from b where id in (select id from a where ....);//这样用in是可以的,子查询的结果是一个列表(1,2,3).

2, select * from b where id in (select group_concat(id) from a where ...);//这样错误的,得不到想要的结果,因为子查询的结果是一个整体字符串("1,2,3"),而非一个列表(1,2,3)

3, select * from b where find_in_set(id, select group_concat(id) from a where ...);//这样写MySQL服务器会报错,语法错误。原因是子查询需要用小括号括起来!!!

4, select * from b where find_in_set(id, (select group_concat(id) from a where ....));//这样是正确的。

4.1, 语法变体

【新增:关于子查询的一个理解】

无论是在select语句还是在update语句中使用子查询,如果子查询的条件中涉及到了多表的连接,那么select语句或update语句执行时是 子查询中查出一个结果 整个SQL语句就执行一次。而如果子查询的条件中的没有多表,那么子查询会首先查询完,然后再执行整个SQL语句。例子如下:

select col1 from tab1 where col1=(select col2 from tab2 where tab2相关条件);//首先查询出子查询中的所有结果,然后执行整个SQL语句,如果子查询中的结果超过一条,会报subquery结果超过一条,此时可以在子查询前面加个any修饰一下。

select col2 from  tab2 where col1=(select col2 form tab2 where tab1.col3=tab2.col3);//子查询的条件中有两个表的连接,执行时是子查询查到一条,就将整个SQL执行一次。然后逐个循环。

update语句也是一样:如下

update tab1 set col1=(select col2 from tab2 where tab2相关条件);//首先查询出子查询中的所有结果,然后执行整个SQL语句,如果子查询中的结果超过一条,会报subquery结果超过一条,此时可以在子查询前面加个any修饰一下。

update tab1 set col1=(select col2 from tab2 where tab1.col3=tab2.col3);//执行时是子查询查到一条,就将整个SQL执行一次(更新一次)。然后逐个循环。

构造子查询命令的方法有很多种,以下是一些重要的语法变体(较新版的MySQL可以在部分子查询命令中使用LIMIT)。

※ SELECT ... WHERE colA operator [ANY | SOME | ALL] (SELECT ...) //子查询用()括起来。

operator是操作符,如”=“,”<=“,”<>"等,如果没有SOME/ANY/ALL修饰,子查询返回值必须是一个离散值(一行一列)。

如果修饰符是ANY或SOME(两者是同义词),子查询可以有多条记录(多行一列),colA 与子查询的的所有结果的关系是或者关系,比如说operator是"<",查询结果有3个,分别是1,2,3, 那么只要是colA < 1或者colA <2 或者 colA <3中的任意一个成立,WHERE条件就成立;如果修饰符是ALL,查询结果也可以有多条记录(多行一列),colA与所有查询结果的关系是并且关系,还是上个例子,那么只有colA<1 并且colA<2并且colA<3同时成立,WHERE条件才成立,对与ALL修饰符,还有一种情况需要考虑,即子查询的结果为空,那么就相当于没有WHERE条件,即 直接执行不带WHERE条件第一个SELECT命令。

※SELECT ... WHERE colA [NOT] IN (SELECT ....)

※SELET ROW(value1, value2, ...) = [ANY | SOME] (SELECT col1,col2, ...)

这个查询将测试是否测在一条能满足给定值的记录,返回结果是1或0。如,SELECT ROW('tong', 11) = (SELECT name,age FROM user WHERE useid=1)。如果用ANY或SOME修饰(这个命令不能用ALL修饰),表示给定值只要在子查询的结果里就返回1,这条命令只能对2个字段及以上使用,单个字段应该用其他命令。

※SELECT ... WHERE [NOT] EXISTS (SELECT ...)

第一条SELECT命令查到多少条记录,第二条SELECT命令就要执行多少次。只有当第二条SELECT命令有结果(至少找到一条记录)时,第一条SELECT命令找到那条记录才能进入最终的查询结果。这种EXISTS语法结构一般只有在那两条SELECT命令所涉及的记录可以用WHERE条件相关联(就像JOIN操作一样)时才有实际意义。例如,

SELECT title FROM titles WHERE  EXISTS (SELECT * FROM publishers WHERE titles.publID=publishers.publID AND publName like 'O%');这条命令中的第二个SELECT命令 将为titles数据表中的每一条图书记录执行一次,只有当这第二条命令返回非空的结果时,第一条SELECT所返回的那本图书才会被返回到结果中。

再举一个没有实际意义的例子,但能加深对这个命令对理解:

SELECT title FROM titles WHERE EXISTS (SELECT 1);//第二个SELECT命令始终都有结果,所以第一个SELECT中的每一条记录都会被返回到最终结果中,这个命令等价于SELECT title FROM titles.

※SELECT ... FROM (SELECT ... ) AS name WHERE ...。

MySQL将先执行括号中的第二条SELECT命令,他将返回一个临时数据表作为外层SELECT命令的查询对象。这种临时数据表被称为衍生数据表(derived table)。SQL语法要求衍生数据表必须通过AS name子句获得一个名字

4.2, SELECT命令还可以用在UPDATE和DELETE命令的WHERE条件里,以确定需要对哪些记录进行修改或删除。但是需要注意,打算修改的数据表和子查询所涉及的数据表必须不同!

有些涉及子查询的UPDATE命令不是很好理解,下面举两个例子加深理解:

①假设tb1,tb2是两个完全一样的表,里面有两个字段col1,col2

UPDATE tb1 SET col1 = ( SELECT col2 FROM tb2 WHERE tb1.col1=tb2.col2);//这个命令将会把tb1的col1字段的所有记录值更新为tb2的col2的值,通过 tb1.col1=tb2.col2条件确定对应关系。

②UPDATE fulltitles f SET authorsname=(SELECT group_concat(authname) FROM rel_title_author r,authors a WHERE r.titleid=f.titleid AND r.authid=a.authid GROUP BY title); //fulltitles是图书数据表, authors是作者数据表,res_title_author是两者的关系数据表。

4.3, 子查询的执行效率非常低下。或许是因为子查询比普通的关联查询(SELECT ... JOIN)更难以让MySQL进行优化。所以,应尽可能使用等效的SQL命令而不是使用子查询。

4.4,查找冗余数据

※SOUNDEX()函数:针对英文单词,此函数能够根据给定的文字的读音返回一个字符串,可以把读音类似的记录找出来,但是不是很靠谱。

※注意,字符串之间是可以比较的,如大于,小于,MAX(), MIN()等都可以用在字符串上。它们之间比较的依据是校验规则collation。比如,utf8_bin,则会比较字符串之间的utf8b编码的大小


5,以随机方式选择数据记录

5.1,通用方法:使用RAND()函数:

SELECT * FROM tbname ORDER BY RAND() LIMIT 2; 这条SQL命令每次随机返回2条记录。在比较大的数据表上用此方法随机选择记录效率很低,因为MySQL必须把所有的记录都读入内存并在那里按随机顺序对它们进行排序,而这一切只是为了选取一条记录。

5.2,自备随机数的数据表

作者介绍了这一种方法,但是自己发现并没有作者介绍的这么简单,作者对RAND()函数的理解出错了!先介绍下作者的方法:

给数据表专门添加一个用来存放随机数的数据列(起名为random),并给它加上索引,SQL命令如下,

ALTER TABLE tb ADD random DOUBLE;

ALTER TABLE tb ADD INDEX (random);

UPDATE tb SET random = RAND();

然后就可以用如下命令来选取一条随机记录:

SELECT * FROM tb WHERE random > RAND() ORDER BY random LIMIT 1;

自己测试时发现(测试时去掉了ORDER BY random这一条件),这条命令取出的随机数基本就在不超过3个固定的记录之间产生,这必然不合理,肯定不是随机。问题出在对RAND()函数的理解上!上面选取随机记录的命令中,对于每一条记录来说,RAND()每次都会生成一个新的随机数,而不是在一次查询中RAND()对所有记录都是同一个值,简单验证下即可证明:SELECT RAND() FROM tb;此时RAND()的值并不是同一个。所以,如果把tb中的第一条记录的random的值手动设置成0.999999,那么上面的那条命令每次“随机”选取的都是第一条记录!当然按作者写的那样,加上ORDER BY random这一条件之后情况会好些,因为第一条记录的random值是表中最小的,那么它的random>rand()的记录就小点,所以看着还挺“随机”的,实际上并不是真正的随机,当然,对于一些要求不高的地方可以这么用,但是random比较大的那些记录基本没有机会被选中!

另外,RAND()函数是可以接收一个参数的,比如RAND(1),如果传入字符串或小数会被转化为整数。加入参数后RAND()每次都会返回同样的值,即使是不同的人不同的连接(session)其返回值也是相同的。但有一点要注意:带有参数比如RAND(1)的返回值每次都是固定的,比如, SELECT RAND(1),RAND(1),RAND(1) UNION ALL SELECT RAND(1),RAND(1),RAND(1)发现6个RAND(1)的值都是相同的,但是如果你用命令SELECT RAND(1) FROM tb LIMIT 5;会发现5个RAND(1)的返回值并不相同,但是呢,如果后面无论 再执行多少次SELECT RAND(1) FROM othertb LIMIT 6,会发现它和之前的5个值一直是相同的。也就是说,RAND(1)的值其实像数组,选取时可以选取数组第一个值,也可以选取多个值,但数组本身的各个值是一直不变的。

5.3, 利用id数据列选择随机记录

作者的这种做法同样是错误的,即假设表里有一个AUTO_INCREMENT的字段id,里面有1000条记录,使用SELECT * FROM tb WHERE id=CEILING(RAND() * 1000);随机选择一条记录。错误同样是因为RAND()函数:对于每一条记录来说,RAND()函数的值都是不同的,这个命令的选取过程是对表中的每一条记录检测是否满足每次都有不同值的RAND()函数的关系式:id=CELING(RAND()),返回结果是有时候一条记录都么有,有时候有好几条记录。

 


6, 全文索引(full-text index),MySQL5.6之后InnoDB开始支持全文索引

SELECT * FROM tb WHERE col LIKE "%word%" // 这个命令大概是MySQL数据库里最消耗时间的查询:MySQL不仅需要 把数据表里的所有记录全都读取过来,还需要进行无数的字符串比较操作,而这些还没有索引可以帮得上忙。如果想在MySQL里对这类查询做出高效率的处理,就需要使用全文索引:这是一种特殊的索引,它会把在某个数据表的某个数据列里出现过的所有单词生成一份清单。

 6.1,基础知识

 6.1.1, 创建全文索引

ALTER TABLE tbname ADD FULLTEXT(col1, col2);

6.1.2, 使用全文索引

  SELECT * FROM tbname WHERE MATCH(col1,col2) AGAINST ('word1 word2 word3' [search_modifier])[ > 0.001]  //此命令将把col1,col2数据列至少包含着word1, word2,word3这三个单词之一的数据记录全部查找出来。关键字AGAINST后面列出的被检索单词不区分大小写(如果要区分大小写,需要字段本身能够区分出大小写,如加binray属性或collate latin1_bin),先后顺序也无关紧要。

search_modifier:即搜寻模式,有三种

①IN NATURAL LANGUAGE MODE

   NATURAL LANGUAGE MODE 全文检索中的默认类型。把查询字符串作为一个短语,如果有不少于50%的行匹配,则认为没有匹配的,过多的匹配结果没有意义,这个词几乎被当作是stopword。想去掉50%的限制,可以修改文件myisam/ftdefs.h里的#define GWS_IN_USE GWS_PROB#define GWS_IN_USE GWS_FREQ

 

②IN BOOLEAN MODE

③IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION 或者简写为 WITH QUERY EXPANSION 

对自然语言检索的一种改动(自动相关性反馈),当查询短语太短时有用。先进行自然语言检索,然后把最相关的一些(系统变量ft_query_expansion_limit的值)行中的词添加到查询字符串中进行二次自然语言检索,查询得到的行作为结果返回。换种解释方法:先用IN NATURAL LANGUAGE MODE做搜寻,得到最相关的字段的字再加到原expr里,再查一次。 
神奇功能之一:可以用database查出mysql或oracle,第一次查询用databae得到一些结果,从这些结果里抽取字符串,此时得到mysql与oracle的机率相当高,最后用database和这些出取出来的字符串做一次查询。 
神奇功能之二:无法拼出正确字符串时,第一次用「相似」的错误字符串查询,很有可以得到正确的字符串,再用正确的字符串急可以得到想要的结果。 
因为这种查询方式会让「噪声」爆增,所以建议第一次的查询字符串尽量精简。 

MATCH... AGAINST...表达式将返回一个浮点数作为它本身的求值结果,这个数字反映了结果记录和被检索单词的匹配程度。如果没有匹配到任何记录或者是如果匹配到的结果记录太多反而被忽略,MATCH... AGAINST...表达式将返回0. 条件表达式MATCH.. > 0.01的作用是排除那些MATCH返回值太小的结果记录,这有助于减少浮点数误差对检索结果的影响。

注意点:MATCH(col1,col2)要能执行,前提是创建了一个包括且仅包括这两个数据列的全文索引,包含更多个数据列的全文索引、分别为这两个数据列建立的全文索引都不能使用

6.1.3, 对全文检索结果进行排序

SELECT *, MATCH(col1, col2) AGAINST('word1 word2 word3') AS mtch FROM tbname HAVING mtch > 0.01 ORDER BY mtch DESC LIMIT 5; 注意,这里只能用HAVING,因为mtch是查询结果中的字段名而不是表中的字段名。

6.1.4,布尔检索表达式

默认情况下,AGAINST后面列出的被检索单词按逻辑或(OR)关系相互组合。MySQL4.0以后还有一个布尔检索模式,需要在被检索单词(这些单词是用布尔表达式组合在一起的)后面加上IN BOOLEAN MODE 字样,下表列出了如何构造布尔检索表达式:

mysql学习笔记_第16张图片

一个布尔模式的全文检索命令例子:

SELECT * FROM tbname WHERE MATCH(col1,col2) AGAINST('+word1 +word2 -word3' IN BOOLEAN MODE)

布尔检索的MATCH表达式只返回1或者是0,表示找到匹配记录和没有找到匹配记录而不是返回一个表示匹配程度的浮点数。

6.1.5,同时对多个数据表进行全文检索

WHERE条件中多个MATCH...AGAINST一起用,没什么特别的。但是同时对多个表进行全文索引速度也是非常慢的,最好还是用其他代替方法。

6.1.6,全文检索在默认的情况下只会对4个或更多个字母的单词进行搜索,可以通过配置文件修改 

mysql学习笔记_第17张图片

在MySQL配置文件的[mysqld]段落里输入或修改参数ft_min_word_len,对于InnoDB数据表则是修改innodb_ft_min_token_size;为了让修改生效,需要重启MySQL服务器并重新生成全文索引:对于MyISAM数据表来说最简单的重新生成全文索引的方法是SQL命令REPAIR TABLE tablename QUICK,这个命令对于InnoDB数据表是不能用的,InnoDB数据表可以先drop掉原来的fulltext索引,然后重新生成全文索引。

6.1.7, 其实讲了这么多,上面这些全文检索的命令都是针对英文或类英文这种以空白分割单词的语言,而汉语是没有空白的,所以全文索引并不能直接用于汉语。可以另加一个字段存储汉字的某种编码( 拼音 / 区位 / urlencode / base64_encode / json_encode 等方案)但是最好的解决方案是:中文分词。至于如何用,再另行研究吧。

从MySQL 5.7开始,MySQL内置了ngram全文检索插件(N-gram是中文检索常用的分词算法,已经在互联网大量使用),用来支持中文分词,并且对MyISAM和InnoDB引擎有效。

下面简要介绍下MySQL的ngram插件:参考  http://blog.csdn.net/h106140873/article/details/69053935

首先在配置文件里设置ngram的分词大小

[mysqld]

ngram_token_size = 2

注意,重新设置了大小之后,需要重启MySQL服务器并且并且需要重新生成全文索引

带有ngram全文索引的创建方法为:

ALTER TABLE tbname ADD FULLTEXT() WITH PARSET ngram

然后就可以插入中文数据测试了。

通过系统数据库INFORMATION_SCHEMA中的数据表,我们可以查到MySQL为我们生成的全文索引,具体方法如下:

首先设置:SET GLOBAL innodb_ft_aux_table="dbname/tbname"

然后就可以通过SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE(或INNODB_FT_INDEX_CACHE)查看了。如果把ngram_token_size设为2,那么此表中的索引字都是2字词,把所有可能的2字词都生成一个索引,比如某个字段内容为   “中华人民共和国”,其生成的索引如下截图所示: 

mysql学习笔记_第18张图片

 


 7, 锁定(LOCKING)  

参考网站:http://blog.csdn.net/zyz511919766/article/details/16342003

MySQL是一个采用了客户/服务器体系结构的数据库系统。这意味着多个程序可以同时去访问数据库、读取数据和进行修改。这么以来,万一有两个程序(客户端)在同一时间去修改同一项数据就会导致一系列问题(最直接的例子是飞机票)。

针对这类问题的解决方案有很多种,其中最巧妙同时也往往是最有效率的办法就是事务处理机制。MySQL数据库系统的事务处理机制目前还只能在InnoDB数据表上使用。而MyISAM数据表就只能依靠所谓的 锁定 机制。

7.1, 语法  

为了保留一个或多个数据表仅供一个客户端使用,需要执行以下命令:

LOCK TABLE[S] tb1 [AS alias] locktype, tb2 locktype ....; //锁定之后就只能对加锁的 表进行操作,操作完之后解锁表才能对非加锁的其他表进行操作

locktype代表锁定类型,可供选用的锁定类型有以下几种:

※READ。被锁定的数据表对全体MySQL用户可读,但不允许修改(发出LOCK命令的那个客户端也包括在内)。多个session可以同时为同一个表设置READ锁。第一个session设置了read锁,第二个session若试图设置write锁也会被阻塞,直到第一个session解除锁。

※READ LOCAL。类似于READ锁定类型,但允许不影响任何现有数据记录的INSERT命令执行。

※WRITE。被锁定的数据表允许当前用户进行读和写,其他用户则完全被排除在外:既不能读取数据表中的数据,也不能对数据进行任何修改。不能同时在多个session中为同一个表设置WRITE表。第一个 session对表设置了write锁之后,其它的session再对同一个表设置read或write锁就会被阻塞,直到第一个session解除锁。而且,其他的session中等待的write锁要优先read锁被执行。

※LOW_PRIORITY WRITE。LOW_PRIORITY 修饰符用于之前的版本,影响锁定行为。但在MySQL5.6.5之后便不在使用该选项。

解除锁定的命令是:UNLOCK TABLE[S];

7.2,简单使用

※LOCK TABLE[S]语句可以作用于table,也可以作用于view和trigger。对于view和trigger,会将其所使用的所有基表加锁。

※LOCK TABLE[S]语句在为当前session设置新锁前会隐式的释放当前session之前的所有锁。若session断开连接,无论是正常断开还是异常断开,服务器都会隐式地释放该session保持的所有锁,即使客户端重新连接也不会再重新获得这些锁。

※对某个表使用了锁定之后,在解除锁定之前的所有操作就只能用在被锁定的表上。而且不能在单条查询中使用相同的名称多次引用锁定的表。比如:

解决方法是使用LOCK TABLE[S]时为表使用别名且为别名设置单独的锁。例如:

mysql学习笔记_第19张图片

※MySQL在执行单条命令时总是不让它收到任何其他命令的影响。因此在执行单挑命令的时候不必使用锁定机制。只有当需要连续执行多条彼此独立的命令,而且在这些命令的执行过程中不允许其他客户端修改正在使用的数据时,才需要使用锁定机制。比较典型的情况是:需要在执行完一条SELECT命令后立刻使用一条UPDATE或DELETE命令对其查询结果进行修改。

※不要对InnoDB数据表使用LOCK和UNLOCK命令,这么做会让MySQL和InnoDB的锁定机制相互干扰。LOCK命令会终止当前事务。对于InnoDB数据表,应该尽量使用事务来锁定各有关记录(而不是锁定整个数据表)。如果真的需要锁定整个InnoDB数据表,MySQL从5.0.3版本开始提供了一条新的命令:LOCK TABLE[S] TRANSACTIONAL.

 


7.3,MySQL中的共享锁

如果只需要锁定两个进程之间的通信,最好不要使用LOCK/UNLOCK命令而是使用GET_LOCK和 RELEASE_LOCK 函数。MySQL对外提供了一种应用层级别的共享锁,通过这个共享锁,数据库之上的应用程序可以实现互斥功能。这个共享锁通过一组MySQL内置函数实现。

GET_LOCK(name, timeout)函数:这个函数的作用是获取共享锁,其中的name是应用程序通信双方协商好的一个字符串,timeout是等待该锁的超时时间。

  • 如果能在timeout时间内获取到锁,则返回1;
  • 如果在timeout时间后仍然获取不到锁,则返回0;
  • 如果发生错误,则返回NULL。

一个应用程序获取到锁后,可以通过RELEASE_LOCK(name)、执行新的GET_LOCK(othername, timeout)、或者mysql连接被释放时(无论是正常释放还是异常断开)这三种方式释放共享锁。注意,执行新的GET_LOCK(othername, timeout)之后,原来的名为name的锁将自动被释放,也就是说同一个session共享锁只能存在一个

RELEASE_LOCK(name)函数:解锁名为name的的共享锁。

  • 如果锁被成功释放,返回1。
  • 如果该进程没有占有该锁,则返回0。
  • 如果这个名为name的锁不存在,则返回NULL。

IS_USED_LOCK(name)函数:检测名称为name的锁是否被使用以及被哪个session使用

  • 返回结果为session连接的id,表示名称为name的锁正在被此连接使用
  • 返回结果为NULL,表示名称为name的锁没有被使用。

IS_FREE_LOCK(name)函数:检测名称为name的锁是否闲置

  • 返回结果为1,表示此锁处于闲置状态,可用
  • 返回结果为0,表示此锁处于被使用状态,不可用。

这两个函数所定义/释放的锁与数据表无关,MySQL服务器、数据库和数据表都不会因为它们而被锁定。

 


8,事务(TRANSACTIONS)

只有InnoDB数据表支持事务,MyISAM数据表不支持事务。

8.1, 事务的好处

事务符合ACID原则,

mysql学习笔记_第20张图片

mysql学习笔记_第21张图片


8.2,事务的控制

8.2.1, 在默认的情况下,MySQL将以自动 提交模式(auto commit) 模式运行(SHOW VARIABLES LIKE "autocommit"可以查看本次session的其值)。

这意味着每一条SQL命令都将被当做一个只包含一条命令的的小事务来执行。有两种方法可以把多条SQL命令集合为一个事务来执行:

  • ①可以使用GEGIN或START TRANSACTION命令开始一个事务,这两个命令将为本格事务暂时关闭“自动提交”模式。用COMMIT 或 ROLLBACK命令来结束这个事务。如果想开始另外一个事务,就必须用另外一条BEGIN命令作为开始。
  • ②可以关闭自动提交模式(使用 SET autocommit = 0 )。在此之后执行的所有命令都被认为是同一个事务,直到遇到COMMIT命令(提交事务)或ROLLBACK命令(放弃事务)为止。

8.2.2, 对InnoDB数据表不允许以嵌套方式使用事务。如果在还没有为前一个事务发出过COMMIT或ROLLBACK命令之前又用BEGIN命令开始了一个新的事务,前一个事务将按COMMIT方式结束。

事务由客户端负责管理,如果客户端与服务器之间的连接在某个事务尚未结束时掉了线,所有未被提交的修改将被放弃(就好像发出了ROLLBACK命令那样)。

8.2.3,存档点(savepoint)

从MySQL4.0.14版开始,InnoDB 数据表驱动程序开始支持savepoint机制:用户可以在事务里用SAVEPOINT name 命令设置一些存档点,以后当用户使用 ROLLBACK TO SAVEPOINT name 命令结束事务的时候,发生在存档点name之前的修改将被写入数据库,而发生在之后的则被放弃。SAVEPOINT命令只能在事务里使用,在事务结束时,所有的存档点都将被清除。

8.2.4, 事务的自动终止

事务还会因为一下命令而自动终止(视同执行了COMMIT命令):ALTER TABLE / CREATE INDEX / CREATE TABLE /DROP DATABASE / DROP TABLE / LOCK TABLE[S] / RENAME TABLE tb1 (to) tb2 / SET autocommit = 1 / TRUNCATE / UNLOCK TABLE[S]。但在另一方面,事务不会因为事务内的某条SQL命令在执行时发生的简单错误而终止。


8.3, 事务与锁定

8.3.1,MySQL中的行级锁、页级锁、表级锁

参考网站:https://www.cnblogs.com/wang-meng/p/5506927.html

在DBMS中(Database Management System,数据库管理系统),可以按照锁的粒度把数据库锁分为行级锁(InnoDB引擎)、表级锁(MyISAM引擎)和页级锁(BDB引擎)。

MySQL中三种级别的锁
  描述 特点
行级锁 行级锁是MySQL中锁定粒度最细的一种锁,表示只针对当前操作进行加锁.行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排它锁 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高
表级锁 表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排它锁) 开销小,加锁快;不会出现死锁;锁定粒度大, 发生锁冲突的概率最高,并发度最低
页级锁 页级锁是MySQL中锁定粒度介于行级锁和表级锁之间的一种锁。表级锁速度快,但冲突多,行级锁冲突少,但速度慢。页级锁是一种折衷的方案。一次锁定相邻的一组记录。BDB支持页级锁 开销和加锁时间介于表级锁和行级锁之间;会出现死锁;锁定粒度介于两者之间,并发度一般

MyISAM和MEMORY采用表级锁;

BDB采用页面锁或表级锁,默认为页面锁;

InnoDB支持行级锁和表级锁,默认为行级锁。

8.3.2,InnoDB中的行锁和表锁

InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点和Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,如果一条SQL语句用不到索引是不会使用行级锁的,而是会使用表锁

8.3.3,InnoDB的锁定行为控制

InnoDB数据表驱动器除了设置了一些默认值外(即普通的SQL语句),提供了几种可以用来调控其锁定行为的办法:以下都假设A为开启了一个事务的session,B为另外一个session。所有的可能情况键下表

事务锁定行为一览表
  B 普通SELECT SELECT .. LOCK IN SHARE MODE SELECT ... FRO UPDATE 修改操作(UPDATE / INSERT / DELETE)
A          
普通SELECT   B的查询不受影响 B的查询不受影响 B的查询不受影响 B的修改不受影响

SELECT ... LOCK IN SHARE MODE

(A给相关记录加了一把共享锁)

  B的查询不受影响 B的查询不受影响 B的查询被阻塞,直到A的事务结束 B的修改被阻塞

SELECT ... FOR UPDATE

(A给相关记录加了一个排它锁)

  B的查询不受影响 B的查询被阻塞 B的查询被阻塞 B的修改被阻塞

修改操作(UPDATE / INSERT / DELETE)

(A给相关记录加了一把排它锁,如果修改的命令需要检查数据之间的关联/引用关系--即外键约束条件--那么所有关联数据表里受其影响的数据记录也都将被加上一把排它锁)

 

B的查询不受影响,不受A尚未提交或撤销的事务的事务影响,这么作的好处是用户不会迟迟看不到结果,坏处是用户看到的结果可能已经过时了

B的查询被阻塞 B的查询被阻塞 B的修改被阻塞

8.3.4,防插入锁(gap and next key lock)

在隔离模式为REPEATABLE READ 和 SERILIZABLE的模式中(下面有介绍),InnoDB数据表驱动程序在遇到带有范围条件表达式(如WHERE id > 100)的SELECT ... LOCK IN SHARE MODE、SEELCT ... FOR UPDATE 、UPDATE或DELETE命令时还会多给它们加上一把防插入锁。加上这把锁的效果是:不仅符合给定条件的现有数据会被锁定,连符合条件但当前并不存在的数据记录也会被锁定,而这意味着其他事务将无法在有关的数据表里插入符合给定条件的数据记录。

8.3.5,死锁

InnoDB数据表驱动程序能够自动识别死锁(deadlock,两个或多个进程互相阻塞,彼此都在等待对方结束,结果是谁都无法继续执行)条件并加以消除:触发死锁的那个进程(后来者)将收到一条出错消息,该进程尚未提交的所有SQL命令按ROLLBACK方式撤销,另一个进程(先来者)将继续执行。

不过如果死锁是因为一些既访问InnoDB数据表又访问其他类型数据表的SQL命令而引起的,InnoDB数据表驱动程序不一定能把它们识别出来。可以通过配置参数:innodb_lock_wait_timeout = n 来设置一个最长等待时间。


8.4, 事务的隔离模式

在开始一个事务前,必须先为它定义一个隔离模式:

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL

READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE

这个SET命令和普通的设置系统变量的SET命令还不太一样,这个命令中的SET命令有三种用法:

  • ①不带关键字SESSION 或 GLOBAL的SET命令。SET命令设置的隔离模式将只对下一个事务有效。
  • ②SET SESSION。为当前连接会话设置隔离模式,其效力将一直持续到下一条用来设置隔离模式的SET命令或当前连接会话结束,即客户端与服务器断开连接。
  • ③SET GLOBAL。为此后所有新建的MySQL连接设置隔离模式(当前连接不包括在内),直到服务器重启。

隔离模式的影响力体现在事务命令的执行方式上。隔离模式按照 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE的顺序,READ UNCOMMITTED能获得最快的访问速度(不会彼此阻塞),而隔离模式SERIALIZABLE在多个客户端同时进行修改时能获得最大的安全保障。各个隔离模式的具体介绍如下:

mysql学习笔记_第22张图片

默认情况下,InnoDB使用REPEATABLE READ隔离模式。此模式兼顾速度和隔离效果。可以通过MySQL配置文件里的 transaction-isolation选项来改变这一默认设置。注意名字有所变化,要使用连字符:

transaction-isolation = read-uncommitted | read-committed | repeatable-read | serializable

另外还可以通过设置系统变量 tx-isolation来设置不同的隔离模式。

set tx-isolation = " read-uncommitted | read-committed | repeatable-read | serializable "


8.5,事务出错处理

使用事务的时候,服务器返回某些特定出错消息的概率会比平时增加许多。因此在编写代码的时候要对命令的执行情况进行检查,即使是不那么关键的SELECT命令,根据从服务器返回的出错消息做出妥善处理。

 


 


 


 

第四章,访问安全与信息安全

为了保护数据不被探查或篡改,MySQL采用了一种双层的访问控制机制。第一层次用来检查各个用户是否有权与MySQL进行通信;第二层次用来检查各个用户有权对哪些数据库、数据表和数据列进行哪些操作。

1,简介

1.1,客户端与MySQL服务器之间的连接

客户端与MySQL服务器之间的连接协议有四种:tcp, socket, pipe, memory。

1.1.1, 当客户端程序和服务器是在不同的计算机上运行的时候,两个程序之间的连接必须要通过网络协议TCP/IP。需要满足两个条件:

1.1.2, 本地计算机(localhost)上的连接

当客户端程序和服务器是在同一台计算机上运行的时候,可以有一下几种方法:

mysql学习笔记_第23张图片

 

1.2,访问管理

MySQL提供了一个 访问权限系统(access privileges system) 来控制访问权限。这个系统就是安装完MySQL后的mysql数据库。通过mysql这个数据库中的各个表来控制权限。

1.2.1,设置访问权限

mysql学习笔记_第24张图片

1.2.2,主机名

※当客户程序和服务器是运行在同一台计算机上的时候,对于主机名有点糊涂。自己的理解如下(不一定正确):

使用-h指定的也可以视为指定的是远程主机名(服务器名),由于服务器和客户端是同一台机器,所以当使用了-h指定了服务器的名称之后,客户端的名称也就被指定了(因为两个是同一台机器,即-h localhost即客户端的名称就是localhost,-h 192.168.1.111则客户端的名称也是192.168.1.111)。mysql数据库中的user表中的host字段存储的仍然是MySQL服务器允许的客户端的名称。如果host字段是localhost,那么使用-h 192.168.1.111是无法登录MySQL服务器的。

※当客户程序和服务器是运行在不同的计算机上的时候,关于主机名如下:

mysql -h可以指定远程主机名(即服务器的名称)。mysql数据表中的user数据表中的host字段存储的是此服务器允许的 客户端的主机名或IP。在建立连接的过程中,服务器会首先接受客户程序的IP地址。然后和host字段比对。匹配一致才允许连接。


 

2,急救

2.1,只允许某个用户创建特定前缀的数据库:

关键点在于:mysql数据库中的user数据表中的create_priv字段要为"N"(否则便会有全局的create权限),然后往db数据表中插入数据,如下:

 

-- 这里假设用户名为ths
INSERT INTO mysql.db (Host, Db, User, Select_priv, Insert_priv,
Update_priv, Delete_priv, Create_priv, Drop_priv, Grant_priv,
References_priv, Index_priv, Alter_priv, Create_tmp_table_priv,
Lock_tables_priv, Create_view_priv, Show_view_priv)
VALUES ('localhost', 'ths%', 'ths', 'Y', 'Y', 'Y', 'Y',
'Y', 'Y', 'N', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y');

 

这里在db数据表中为用户ths@localhost设置了 创建数据库 的前缀,即只有以ths开头的数据库才能被创建,否则创建数据库的请求会被拒绝。

FLUSH PRIVILEGES;使更改立即生效![MySQL启动时将mysql权限数据库读入内存,flush命令可以立即更改内存使之生效]


 

 

3, 访问控制机制的内部工作原理

3,1, 权限

MySQL的访问权限是由mysql数据库实现的,其中的各个数据表对应着权限的各个方面。

3.1.1, mysql数据库中的各个数据表概览

名字 含义
user 控制谁(用户名)可以从哪一台计算机(主机名)访问MySQL。这个数据表也包含着全局权限
db 规定哪个用户可以访问哪个数据库
tables_priv 规定谁可以访问数据库的哪一个数据表
columns_priv 规定谁可以访问数据表的哪一个数据列
func 使之具备UDFs管理(user-defined-functions)
procs_priv 规定谁可以执行单个的的存储过程
  • 安装了新的MySQL之后,user和db的默认值取决于操作系统。tables_priv, columns_priv数据表的初始内容都是空。
  • 在MySQL的两级访问系统中,对于第一级访问系统只用到 了user数据表。对于第二级访问系统来说,要用到所有的表:即user,db,tables_priv,columns_priv。
  • 注意,权限是依照user, db, tables_priv, columns_priv的顺序依次实施的。换句话说,如果Select权限赋予了user数据表中的一个用户,那么其他的3个数据表就不再用于检查这个用户是否允许执行SELECT命令。因此,要想对访问权限进行精确的区别,就必须把user数据表里的全局权限全部设置为N。

3.1.2, user数据表(原书11.3.4, p277)

※访问控制

mysql学习笔记_第25张图片

user数据表中的检查顺序,更具体的信息在mysql的官方文档里有。

mysql.user数据表在MySQL内部已经排序好了,当从客户端接受到一个user@hostname之后,MySQL服务器首先比对mysql.user中的host字段,规则是:首先检查Host字符串是唯一的条目,然后是使用通配符(%和_)的Host条目。这两组当中,唯一的User字符串优于使用通配符(或为空)的字符串。

※权限

User数据表不但用于控制MySQL的访问控制,而且也用于权限。xxx_priv的权限如果是Y,则代表此MySQL用户的xxx权限是全局的(对所有数据库,数据表,数据列)。如果是N,则此用户xxx的权限不是全局的,进一步由db,tables_priv,columns_priv三个数据表控制权限。

※SSL加密与X509身份标识

mysql学习笔记_第26张图片

※限制MySQL的使用

※user.Host数据列  各种情况单独介绍 p280

3.1.3, db数据表

如果mysql.user数据表中一个用户没有全局权限,那么就会寻找mysql.db数据表,如果user,host,db三个字段都能匹配,就在其中查找这个用户对这个数据库的具体的权限(SELECT,UPDATE,等等)。其中的db字段可以使用通配符(% , _)来匹配某一类数据库。

为了安全控制能够快速执行,MySQL在RAM中预先对各种mysql数据库中的数据表进行分类(即保持了一个mysql数据库中的各个表的备份)。但是这样做的结果是,只有在MySQL使用FLUSH PRIVILEGESmysqladmin reloadmysqladmin flush-privileges 重新读取这些数据表时,对这些数据表的直接改变才成为动态。在使用GRANT和REVOKE命令时,这种重新读取自动发生。

3.1.4,tables_priv和columns_priv数据表(p285)

3.1.5, procs_priv数据表

此表控制着谁可以执行哪一个存储过程。这个数据表只和哪些在 mysql.user数据表和mysql.db表 中没有权利执行和改变存储过程的用户有关。这时,procs_priv数据表为用户提供了可以执行或改变特定 存储过程的可能性。


3.2, MySQL4.1版本开始的安全密码验证 与 老版本的兼容性问题

p288 11.5详细论述,如有需要查看。

 


3.3, 连接MySQL服务器(亦即mysqld)中出现的问题及排除方法【p290 11.6具体的论述。】

一种排查方法:先停止服务器,在配置文件my.cnf或my.ini中的[mysqld]部分里暂时添加skip-grant-tables,并重启服务器。现在每个人都可以不用用户名和密码访问所有数据。如果访问成功,说明问题出在mysql这个权限验证数据库。当然,这个选项还可以用于忘记root密码时登录,然后修改密码。

skip-host-cache选项:

mysql学习笔记_第27张图片


 3.4, 系统安全性

 ※具有File权限的MySQL用户可以读取和改变本地文件系统中的文件。MySQL服务器(亦即mysqld)在哪个账户下运行(注意,这里并不是登录的mysql用户,而是指MySQL服务器是以哪个账户运行的)就会以这个账户去访问文件系统。所以不要以root权限来运行MySQL服务器。

mysql学习笔记_第28张图片

※网络安全与防火墙

skip-networking

mysql学习笔记_第29张图片




 

第五章,GIS函数[Geographic Information System]

第六章,存储过程(stored procedure, SP)与触发器(trigger)

1,存储过程

1,1,存储过程分为两种类型:过程和函数

SP函数:有返回值,可以内嵌在普通的SQL命令里使用。

SP过程:允许使用引用参数(reference parameter,相当于其他语言里的 形式参数 或 可变参数)和更多种SQL命令(比如SELECT和INSERT),SP过程必须用CALL命令来调用。

1.2, 定义SP函数(在MySQL命令解释器:mysql程序中)

SP代码需要使用分号作为语句的结束,所以需要将mysql程序的命令结束符换为其他的符号这里以"$$"作为结束符

mysql> delimiter $$

一般SP代码写在文本编辑器中,然后使用mysql -uroot -pxxxx db_name < sp.sql 将此文件中的SP代码导入到数据库db_name中。但是这个文件不能在mysql里用source命令引入,因为source命令要求其输入文件里的SQL命令以分号作为分隔符,它不接受delimiter命令。

一个SP函数例子:

 

DROP FUNCTION IF EXISTS shorten;
delimiter $$
CREATE
FUNCTION shorten(s VARCHAR(255), n INT) RETURNS VARCHAR(255) BEGIN IF ISNULL(s) THEN RETURN ''; ELSEIF n<15 THEN RETURN LEFT(s, n); ELSE IF CHAR_LENGTH(s) <= n THEN RETURN s; ELSE RETURN CONCAT(LEFT(s, n-10), '...', RIGHT(s, 5)); END IF; END IF; END$$

 

使用SP函数:SELECT shorten('abcdefghijklmnopqrst', 15)$$

SP的内部存储:MySQL把SP集中存放在mysql.proc数据表中。

 

2,

3,

4,

5,

6,

7,

8,

9,

10,

11,

第七章,管理与服务器配置

 四,程序设计

目录

第一章:PHP

第二章:Perl

第三章:Java(JDBC 和 Connector)

第四章:C语言

第五章:Visual Basic 6/VBA

第六章:Visual Basic .NET 和C#

第一章:PHP

第二章:Perl

第三章:Java(JDBC 和 Connector)

第四章:C语言

第五章:Visual Basic 6/VBA

第六章:Visual Basic .NET 和C#

五,参考资料

第一章:SQL语法指南

第二章:MySQL工具和选项

第三章:MySQL API应用指南


第一章:SQL语法指南

最权威的语法指南是官方文档:https://dev.mysql.com/doc/refman/5.7/en/ 

1,语法

1.1,对象命名规则

1.2,字母大小写

在Windows环境下,因为这种操作系统不区分目录名和文件名里的字母大小写情况,所以MySQL中任何的字母大小写情况是不区分的。

从MySQL4.0开始,windows下的MySQL在创建新的数据库和数据表的时候只使用小写字母来起名字(不管它们在CREATE命令中是如何写出的)。这将简化数据库从Windows操作系统向UNIX/Linux操作系统的迁移。这种自动转换有选项 lower_case_table_names 控制,这个选项在Windows下默认为1(好像也不能在配置文件中设置,如果 写在my.ini中,重启服务器会出错,显示 无法重启且没有报告任何错误。)

对于UNIX/Linux系统来说,MySQL中的对象名可以划分为两大类:

  • ①区分字母大小写。数据库名、数据表名、假名以及MySQL4.1版本开始的变量名。
  • ②不区分字母大小写。SQL命令、函数、数据列名、索引名 以及MySQL5.0版本开始的变量名。

1.3,字符串

字符串两端的单引号和双引号在MySQL中没有区别。

如果在字符串里有引号,则有如下表达方式:

一些特殊字符在字符串里的正确写法(注意是在字符串中,需用引号引起来):

\0 0字节(代码0)  
\b 后退符(代码8)  
\t 制表符(代码9)  
\n 换行符(代码10)  
\r 回车符(代码13) 回车符只回车,即只返回此行最开头
\" 双引号(代码34)  
\' 单引号(代码39)  
\\ 反斜线符(代码92)  

如果x不属于上面的特殊字符,那么\x转义成字符x。

MySQL还允许程序员在SQL命令里使用十六进制的代码,如:0x41424344。但是MySQL不能以这种格式返回SQL查询结果。

1.4,字符集和排序方式

字符集和排序方式可以分开设置。

在SQL命令里,可以对每一个字符串定义字符集,使用函数CONVERT()或是操作符_charset 可以实现这一点,比如下面两个例子是相同的,给出的是在UTF8格式下的内部Unicode编码:

SELECT HEX(CONVERT("中" USING utf8)); // E4B8AD

 

SELECT HEX(_utf8 "中"); // E4B8AD

 

1.5, 数值

MySQL可以使用科学计数法(1.23e10 或1.23e-10)来表示非常大或非常小的值。

MySQL还可以处理带有前缀0x 或是 x'1234' 格式的十六进制数值。根据上下文,这种数值将被解释为字符串或64位整数。

SELECT 0x41, x'41', x'41' + 0; // A A 65

1.6,数值和字符串的自动转换

在对两种不同的数据类型进行操作的时候,MySQL会尽可能地把它们转换为同一种数据类型。

  • 如果两个操作数中有一个是浮点数,那么整数就将自动转换为浮点数。
  • 如果对字符串做运算,则字符串将被自动转换为数值。(若字符串开头不能转换为数值,视其为0),如,SELECT "3.14abc" + 1; // 4.14

1.7,日期和时间

在存储日期和时间值的时候,MySQL非常灵活:无论是数值还是在字符串都可以接受。但是只有有效的日期和时间才可以被接受,比如“2017-2-31”不会被接受,时间“3:33:333"也不会被接受,字符串“0000-00-00 00:00:00”是一个特例,在MySQL中,这种表示是允许的。

1.8, 二进制数据

来自BLOB字段的二进制数据在SQL命令里是按字符串来处理的,但在排序时会区别对待。

1.9,二进制数值

从5.0.3版本开始,MySQL支持数据类型BIT。二进制数值可以写成 b'110010' 的格式。

1.10, 注释语句

SQL命令中写出注释的办法有3种:

  • SQL command   # comment
  • SQL command   /* comment */    ,可以跨越多个语句行。
  • SQL command   -- comment   ,注意:--后面至少要有一个空格。

MySQL还支持一些hack写法,即只有MySQL自己可以认识的SQL命令,其他的SQL软件遇到会当前注释。例子如下:

SELECT /*! colA, */ colB FROM tbname; // MySQL会选择colA和colB,其他的SQL软件看到/**/会当做注释。

1.11,SQL命令末尾的分号

mysql学习笔记_第30张图片


2,操作符

mysql学习笔记_第31张图片

mysql学习笔记_第32张图片

2.1,算数操作符与位操作符

如果算数操作符的某个操作数是NULL,则运算结果将是NULL。此外,在MySQL数据库系统里,以0作为除数的结果也将是NULL,这与许多其他的SQL”方言“的做法不一样。

2.2,比较操作符

比较操作符的返回值是1(即TRUE)或0(即FALSE),与NULL值进行比较的结果还是NULL。但“<=>”和”IS NULL“是两个特例。

在使用<, <=, > , >=以及 BETWEEN(当然还包括所有其他的排序类操作符)等操作符进行的字符串比较操作中(注意是字符串和字符串之间的比较),参加比较的数据列的字符集和排序方式将起作用。如果操作数是用引号括起来的字符串,还必须明确的给出它们的字符集和排序方式。 MySQL不能对使用不同字符集的字符串进行比较。

2.3,使用LIKE操作符进行模式匹配

mysql学习笔记_第33张图片

2.4,使用REGEXP操作符进行模式匹配

REGEXP操作符也不区分字母的大小写,其余和正则规则一样。

2.5,二进制字符串比较

2.6,逻辑操作符

逻辑操作符的返回值是0,1或NULL(当有一个操作数是NULL的时候)。NOT操作符也不例外,即, NOT NULL的返回值仍是NULL。


3,变量和常数

mysql学习笔记_第34张图片

3.1,变量赋值

3.5,结构化变量

mysql学习笔记_第35张图片

3.6,常数

从MySQL4.0版本开始,MySQL可以识别TRUE(1)和FALSE(0)两个常数。


4,MySQL数据类型

mysql学习笔记_第36张图片

mysql学习笔记_第37张图片

mysql学习笔记_第38张图片

4.1,字段的属性,注意,不是所有的属性都适用于所有的数据类型


5,SQL命令汇总(按功能分类)

mysql学习笔记_第39张图片

 

mysql学习笔记_第40张图片

mysql学习笔记_第41张图片

mysql学习笔记_第42张图片

mysql学习笔记_第43张图片

mysql学习笔记_第44张图片

mysql学习笔记_第45张图片

在计算机中,slave翻译成从属的


6,SQL命令指南(按字母表顺序排列,包括使用细节)

※ALTER DATABASE [dbname]  actions

从MySQL4.1版本开始可用。设置保存在文件dbname/db.opt中。可以使用相同的ALTER SCHEMA来取代ALTER DATABASE命令。如果没有dbname,该命令应用于当前数据库。

actions:目前有两个动作可选。

  • [DEFAULT] CHARACTER SET CHARSET指定了哪一个字符集是数据库应当使用的默认字符集。
  • [DEFALUT] COLLATE collatename指定了默认的排序方式。

※ALTER FUNCTION/PROCEDURE name options

mysql学习笔记_第46张图片


※ALTER TABLE tblname tbloptions

mysql学习笔记_第47张图片


※ALTER TABLE tblname ADD newcolname coltype coloptions [FIRST | AFTER existingcolumn]


※ALTER TABLE tblname ADD INDEX [indexname] (indexcols ...)

ALTER TABLE tblname ADD FULLTEXT [indexname] (indexcols ...)

ALTER [IGNORE] TABLE tblname ADD UNIQUE [indexname] (indexcols ...)

ALTER [IGNORE] TABLE tblname ADD PRIMARY KEY (indexcols ...)

ALTER TABLE tblname ADD SPATIAL INDEX (indexcol)

mysql学习笔记_第48张图片


ALTER TABLE tblname ADD [CONSTRAINT [fr_keyname]]

  FOREIGN KEY [c1_keyname]

  (colname1) REFERENCES table2 (column2)

  [ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}]

  [ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}]

 mysql学习笔记_第49张图片


※ALTER TABLE tblname ALTER colname SET DEFAULT value

ALTER TABLE tblname ALTER colname DROP DEFAULT


ALTER TABLE tblname CHANGE oldcolname newcolname coltype coloptions


※ALTER TABLE tblname CONVERT TO CHARACTER SET charset [COLLATE collname]

注释:这条命令会同时改变 表和表中所有的文本数据列 的字符集和排序方式。

mysql学习笔记_第50张图片


※ALTER TABLE tblname DISABLE KEYS

ALTER TABLE tblname ENABLE KEYS


※ALTER TABLE dbname.tblname DISCARD TABLESPACE

ALTER TABLE dbname.tblname IMPORT TABLESPACE

mysql学习笔记_第51张图片


※ALTER TABLE tblname DROP colname

ALTER TABLE tblname DROP indexname

ALTER TABLE tblname DROP PRIMARY KEY

ALTER TABLE tblname DORP FOREIGN KEY foreign_key_name


※ALTER TABLE tblname ENGINE tabletype


※ALTER TABLE tblname MODIFY colname coltype coloptions

该命令的作用和ALTER TABLE ... CHANGE命令一样,唯一的区别在于此条命令中数据列的名字不能改变,所以只需要给出一次名字。


※ALTER TABLE tblname ORDER BY colname

注释:如果数据表有主键,这条命令执行后将不会有效果,并显示一条警告:命令被忽略,数据表已有排序方式。


※ALTER TABLE tblname RENAME AS newtblname

该命令重命名一个数据表(参见 RENAME TABLE 命令) 


※ALTER TABLE tblname TYPE tabletype

这条命令和 ALTER TABLE tblname ENGINE tabletype 命令一样。


※ALTER [algoption] VIEW viewname [(columns)] AS command [chkoption]


※ANALYZE TABLE tablename1, tablename2, ...


※BACKUP TABLE tblname TO '/backup/directory'

mysql学习笔记_第52张图片


※BEGIN


※CACHE INDEX indexspec1, indexspec2 ... IN cachename

mysql学习笔记_第53张图片


※CALL spname [parameter1, parameter2 ...]


※CHANGE MASTER TO variable1=value1, avriable2=value2,...

mysql学习笔记_第54张图片


※CHECK TABLE tablename1, tablename2 ... [TYPE=QUICK]


※COMMIT


※CREATE DATABASE [IF NOT EXISTS] dbname [options]

mysql学习笔记_第55张图片


※CREATE FUNCTION name ([parameters]) RETURNS datatype [options] code

 mysql学习笔记_第56张图片

 mysql学习笔记_第57张图片

mysql学习笔记_第58张图片


※CREATE FUNCTION name RETURNS datatype SONAME libraryname


※CREATE [UNIQUE | FULLTEXT] INDEX indexname ON tablename (indexcols ...)

CREATE INDEX 命令给一个现有的数据库增加一个索引。对于indexname,通常就使用数据列的名字。CREATE INDEX不是一个独立的命令,它只是ALTER TABLE ADD INDEX/UNIQUE命令的一种语法变体


※CREATE PROCEDURE name ([parameters]) [options] code

mysql学习笔记_第59张图片


※CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tblname

(colname1 coltype coloptions reference,

 colname2 coltype coloptions reference ...

[, index1, index2 ...]

) [tbloptions]

 mysql学习笔记_第60张图片

mysql学习笔记_第61张图片

mysql学习笔记_第62张图片


※CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tblname

[(newcolname coltype coloptions reference,

 (newcolname2 coltype coloptions reference ...

 [, key1, key2 ...]

)] [tbloptions]

[IGNORE | REPLACE] SELECT ...


※CREATE [TEMPORARY] TABLE [IF NOT EXISTS] newtable LIKE oldtable

该命令始见于MySQL4.1版本,它将使用现有数据表oldtable的声明定义创建一个空白的新数据表newtable


※CREATE TRIGGER name time event

  ON tablename

  FOR EACH ROW code

mysql学习笔记_第63张图片


※CREATE [algoption] VIEW viewname [(columns)] AS command [chkoption]

mysql学习笔记_第64张图片


※DELETE [deleteoptions] FROM tablename

  [WHERE condition]

  [ORDER BY ordercolumn [DESC]]

  [LIMIT maxrecords]

 mysql学习笔记_第65张图片


※DELETE [deleteoptions] table1, table2 ... FROM table1, table2, table3 ... [USING columns] WHERE conditions

mysql学习笔记_第66张图片


※DESCRIBE tablename [columnname]


※DO selectcommand

 DO是SELECT命令的一个变体,并与其有基本相同的语法。两者之间的区别是命令DO不返回求值结果。例如,命令DO可以用来对变量进行赋值,这时它会比SELECT命令快一点(例如:DO @var:=3)


※DROP DATABASE [IF EXISTS] dbname


※DROP FUNCTION fnname


※DROP INDEX indexname ON tablename


※DROP PROCEDURE prname

删除指定的存储过程


※DROP [TEMPORARY] TABLE [IF EXISTS] tablename1,tablename2...[options]

mysql学习笔记_第67张图片


※DROP TRIGGER tablename.triggername

删除指定的触发器


※DROP VIEW [IF EXISTS] viewname1,viewname2 ... [options]

删除指定的视图,这种删除是不可恢复的。这里可以使用与DROP TABLE 命令相同的选项


※EXPLAIN tablename

mysqlshow -uroot -p1234 dbname [tbname [column]] ;//空格隔开


※EXPLAIN SELECT selectcommand


※FLUSH flushoptions


※GRANT privileges ON objects

TO users [IDENTIFIED BY 'password']

[REQUIRE ssloptions]

[WITH GRANT OPTION] [maxlimits]

另外,FLUSH PRIVILEGES使修改生效。

GRANT 命令用来分配对各种数据库对象(如数据库和数据表)的访问权限。

privileges: 这些权限包括:

ALTER,  CREATE,  CREATE TEMPORARY TABLES,  CREATE VIEW,  DELETE,  DROP,  EXECUTE,  FILE,
INDEX,  LOCK TABLE,  PROCESS,  REFERENCES,  RELOAD,  REPLICATION CLIENT,  REPLICATION
SLAVE,  SELECT,  SHOW DATABASE,  SHOW VIEW,  SHUTDOWN,  SUPER,  UPDATE

如果希望设置全部权限,那么就需要给出ALL,如果希望不设置任何权限,就需要给出USAGE。GRANT本身的权限只能通过WITH GRANT OPTION选项来设置,也就是说ALL并不包括GRANT权限。

如果这些权限只是应用于一个数据表里的某些数据列,那么就把这些数据列放入圆括号内。例如,可以规定GRANT SELECT(columnA,columnB)。


objects:负责给出数据库和数据表。这里可以使用以下几种语法变体:

databasename.tablename 仅在这个数据库的这个数据表
databasename.spname 仅在这个存储过程
database.* 这个数据库的所有数据表
tablename 当前数据库的这个数据表
* 当前数据库的所有数据表(权限其实很小)
*.* 全局权限(除了grant权限之外的所有权限)

较新版的MySQL在objects中允许出现通配符(%和_),需要用``反引号引起来,不然语法错误。 如:grant select on `th%`.* to st@localhost ;


 users: 允许列出一个或多个(需用逗号分隔)用户。如果这些用户在user数据表里尚不存在,则创建它。(新版MySQL会给一个提示:使用GRANT来创建新用户的用法不赞成使用,以后可能会移除此功能,请使用CREATE USER命令创建新用户)。这里可以使用以下几种语法变体:

username@hostname 主机hostname上的这个用户
'username'@'hostname' 同上,但允许名字里包含特殊字符
username 所有计算机上的这个用户
''@hostname Hostname上的所有用户
'' 所有计算机上的所有用户

 


password:使用IDENTIFIED BY 选项,可以对一个指定账户设置明文密码。在GRANT进入到user数据表之前,它使用PASSWORD()函数设置密码。如果指定了多个用户,则需要给出多个密码:

TO user1 IDENTIFIED BY 'pw1', user2 IDENTIFIED BY 'pw2', ...

 


ssloptions:如果与MySQL的连接是加密的SSL或是用胡标识需要X509证书,可以在这里为建立连接规定要求的信息。语法如下所示:

REQUIRE SSL | X590 [ISSUER ’iss'] [SUBJECT 'subj'] [CIPHER 'ciph']

REUQIRE SSL意味着连接方式必须是加密的SSL连接(因此,普通连接是不允许的)。REQUIRE X509意味着用户必须拥有能够满足X509标准要求的有效标识证书。

ISSUER选项指定了要求的证书的签发者。(如果没有ISSUER选项,证书的原件不被认可。)

SUBJECT指定了证书的subject字段所要求的内容。(如果没有SUBJECT选项,证书的内容不被认可)

CIPHER选项指定了要求的SSL加密算法。(SSL支持各种算法。如果没有这项说明,那么所有的算法都是允许的,包括那些可能存在安全漏洞的旧的算法。)

 


maxlimits:在这里可以允许有关用户每小时最多建立多少次连接、发出多少条SELECT命令、发出多少条INSERT/UPDATE/DELETE命令。这三个值的默认值都是0(意思是没有任何限制):

MAX_QUERIES_PER_HOUR n

MAX_UPDATES_PER_HOUR n

MAX_CONNECTIONS_PER_HOUR n

mysql学习笔记_第68张图片


※HANDLER tablename OPEN [AS aliasname]

HANDLER tablename READ FIRST|NEXT [WHERE condition LIMIT n,m]

HANDLER tablename READ indexname FIRST|NEXT|PREV|LAST [WHERE ... LIMIT ...]

HANDLER tablename CLOSE

mysql学习笔记_第69张图片


※HELP

HELP contents

HELP functionname

从MySQL4.1版本开始,HELP返回一个简明的帮助文本。也可以使用其缩写符号?来代替HELP命令。


※INSERT [options1] [IGNORE] [INTO] tablename [(columnlist)] VALUES (valuelist1),(...), ... [options2]

INSERT [options1] [IGNORE] [INTO] tablename SET column1=value1, column2=value2 ... [options2]

INSERT [options1] [IGNORE] [INTO] tablename [(columnlist)] SELECT...

 INSERT命令的用途是往一个现有的数据表里插入新的记录。它有3种主要的语法变体。第一种(也是最常

mysql学习笔记_第70张图片

mysql学习笔记_第71张图片

mysql学习笔记_第72张图片

这里要说明一下VALUES(columnname)函数,文中不知道是旧版本问题还是作者的错误,新版的函数是VALUES()函数,此函数只用在INSERT ... ON DUPLICATE KEY UPDATE ...语句中,在其他地方用返回值都是NULL。注意:这个函数的返回值并不是数据表中已有的字段值,而是书写的INSERT ... ON DUPLICATE KEY UPDATE... 语句中的值。比如,INSERT [INTOT] tablename (colA,colB) values(111, 100),(222,200) ON DUPLICATE KEY UPDATE colB = VALUES(colA) + 1; //这里的VALUES(colA)指的是111和222而不是表中重复的那条记录的colA的值。

最后,说明一下INSERT本身的一个小知识点:对于AUTO_INCREMENT的字段,如果给其显式的传入NULL值,那么其仍会自动生成一个id,不受影响。


※KILL threadid


 https://dev.mysql.com/doc/refman/5.7/en/load-data.html

这个命令涉及到一个变量:secure_file_priv;如果报错需要修改配置文件中的其值为"/"或注释掉这个变量。

LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'

[REPLACE | IGNORE]

INTO TABLE tbl_name

[PARTITION (partition_name [, partition_name] ...)]

[CHARACTER SET charset_name]

[{FIELDS | COLUMNS}

  [TERMINATED BY 'string']

  [[OPTIONALLY] ENCLOSED BY 'char']

  [ESCAPED BY 'char']

]

[LINES

  [STARTING BY 'string']

  [TERMINATED BY 'string']

]

[IGNORE number {LINES | ROWS}]

[(col_name_or_user_var [, col_name_or_user_var] ...)]

[SET col_name={expr | DEFAULT}, [, col_name={expr | DEFAULT}] ...]

mysql学习笔记_第73张图片

mysql学习笔记_第74张图片

mysql学习笔记_第75张图片

mysql学习笔记_第76张图片 


※LOAD DATA FROM MASTER

mysql学习笔记_第77张图片


※LOAD INDEX INTO CACHE indexspec1, indexspec ...

mysql学习笔记_第78张图片


※LOAD TABLE dbname.tablename FROM MASTER


※LOCK TABLE table1 [AS aliasname] locktype, table2 [AS aliasname] locktype, ...

mysql学习笔记_第79张图片

mysql学习笔记_第80张图片


OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE tbl_name [, tbl_name] ...


※PROCEDURE procename

mysql学习笔记_第81张图片


※PURGE MASTER LOGS TO 'hostname-bin.n'


※RENAME TABLE oldtablename1 TO newtablename1, oldtablename2 TO newtablename2, ...

mysql学习笔记_第82张图片


※REPAIR TABLE tablename1,tablename2, ... [TYPE = QUICK]


※REPLACE [INTO]


※RESET MASTER


※RESET QUERY CACHE

该命令删除所有查询缓存区的条目。它需要具有reload权限。


※RESET SLAVE

mysql学习笔记_第83张图片


※RESOTRE TABLE tblname FROM '/backup/directory'


※REVOKE privileges ON objects FROM users

 mysql学习笔记_第84张图片


※ROLLBACK TO SAVEPOINT name


※SAVEPOINT name


※SELECT [selectoptions] column1 [[AS] alias1], column2 [[AS] aliasa2] ...

  [FROM tablelist]

  [WHERE condition]

  [GROUP BY groupfield [ASC | DESC] ]

  [HAVING condtion]

  [ORDER BY ordercolumn1 [DESC], ordercolumn2 [DESC] ... ]

  [LIMIT [offset,] rows]

  [PROCEDURE procname]

  [LOCK IN SHARE MODE | FOR UPDATE]

mysql学习笔记_第85张图片

 mysql学习笔记_第86张图片

mysql学习笔记_第87张图片

mysql学习笔记_第88张图片


※SELECT [selectoptions] columnlist

INTO @var1, @var2 ... 

[ FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT ... ]


※SELECT [selectoptions] columnlist

INTO OUTFILE 'filename' exportopt

[ FROM .. WHERE .. GROUP BY ... HAVING ..ORDER BY ... LIMIT ... ]

这个命令和 LOAD DATA INFILE 'filename' INTO TABLE tblname是一套的。两者的exportopt和importopt格式是一样的。先给出一个例子:

mysql学习笔记_第89张图片

看一下outfile.txt中的格式是什么样的吧:

mysql学习笔记_第90张图片

mysql学习笔记_第91张图片

mysql学习笔记_第92张图片


※SELECT [selectoptions] column INTO DUMPFILE 'filename'

[ FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT ... ]

mysql学习笔记_第93张图片


※(SELECT selectoptions) UNION [ALL] (SELECT selectoptions) unionoptions

mysql学习笔记_第94张图片


※SET @variable1 = expression1, @variable2 = expression2 ...


※SET [options] [@@]systemvariable = expression

mysql学习笔记_第95张图片


※SET [OPTION] option = value

mysql学习笔记_第96张图片

一些重要的 SET 选项,按字母顺序列出来:

SET AUTOCOMMIT = 0 | 1

把事务的自动提交模式切换为关闭或开启状态。自动提交模式只影响那些支持事务的数据表(目前只有InnoDB数据表支持事务,MyISAM不支持事务);

SET CHARACTER SET 'csname'   (注意没有等于号)

把字符集csname赋值给character_set_clientcharacter_set_result这两个会话变量,同时还将把character_set_database的值赋值给会话变量character_set_connection。SET CHARACTER SET DEFAULT重新把3个变量设置成它们的默认值。

SET FOREIGN_KEY_CHECKS = 0 | 1

禁止或激活外键检查功能。

SET SQL_LOG_BIN = 0 | 1

如果使用了镜像机制,可以使用此变量暂时禁用主控系统上的二进制日志,此后的修订将不会被镜像到从属服务器上去。设置为1重新启用日志功能。

SET NAMES ‘csname'

这是SET CHARACTER SET语法的一个变体。区别是字符集csname被分别派到3个会话变量character_set_client、character_set_result以及character_set_connection上。

SET PASSWORD 

此命令对改变密码提供了一个非常简便的方式,不用再进行比较麻烦的访问mysql数据库中数据表的操作。

  • SET PASSWORD = PASSWORD('xxx'); //注:新版本中提倡使用 SET PASSWORD = 'xxx',即不需要函数了。

如果权限足够,还可以使用SET命令来设置另外一个用户的密码:

  • SET PASSWORD FOR username@hostname = PASSWORD('xxx')

SET SQL_QUERY_CACHE = 0 | 1 | 2 | ON | OFF | DEMAND

设置查询缓存区的方式。

SET TRANSATION ISOLATION LEVEL

设置事务的隔离级别。只有在具有事务能力的数据表上才有这个设置。具体内容上面有详细描述。

其他可以使用SET设置的选项:(不常用)

SET BIG_TABLES = 0 | 1

如果设置为1,所有的临时表被存储在磁盘中而不是存储在存储器中。这样会稍微慢些,但是对于需要一个大型临时表的SELECT操作,不会发生 The table tblname is full错误。对于一个新连接,默认值为0(使用存储器内部表)。通常,不必设置此变量,因为根据需要,存储器内部表会被自动转换为以磁盘为基础的表。(注释:此变量以前被命名为SQL_BIG_TABLES)

SET IDENTITY = #

该变量是LAST_INSERT_ID变量的同义词。该变量的作用是保持于其他数据库兼容。

SET INSERT_ID = #

用于设置将被下一个INSERT或ALTER TABLE语句使用的值。此值在插入一个AUTO_INCREMENT值时使用(使用一次后恢复为值0)。本语句主要和二进制日志同时使用。

SET LAST_INSERT_ID = #

用于设定将从LAST_INSERT_ID()被返回的值。当在用于更新表的语句中使用LAST_INSERT_ID()时,它被存储在二进制日志中。设置此变量不会更新由mysql_insert_id() C API函数返回的值

SET SQL_NOTES = 0 | 1

当设置为1时(默认情况),“注意”一级的警报被记录下来。当设置为0时,“注意”警告被压制。mysqldump包含输出,用于把此变量设置为0,这样,对于不会影响重新载入操作整体性的事件,重新载入转储文件时不会产生警告。

SET SQL_AUTO_IS_NULL = 0 | 1

如果设置为1,可以通过使用以下结构查找包含一个AUTO_INCREMENT列的表的最后插入的行:

WHERE auto_increment_column IS NULL // 注意,只显示自动生成的auto_increment列,手动插入后执行此语句会显示查询结果为空。此性质被有些程序,比如Access使用。

SET SQL_BIG_SELECTS = 0 | 1

如果设定为0 ,则MySQL会放弃有可能会话很长时间来执行的SELECT语句(也就时,对于这些语句,优化程序估算被检查的行的数目超过了max_join_size的值)。当一个不妥当的WHERE语句被发布后,本语句有用。一个新连接的默认值时1,这可以允许所有的SELECT语句。如果把max_join_size系统变量设置为除DEFAULT以外的值,则SQL_BIG_SELECTS被设置为0.

SET SQL_BUFFER_RESULT = 0 | 1

此语句会迫使来自SELECT语句的结果被放入临时表中,这可以帮助MySQL早点解除表锁定。当需要花较长时间把结果发送给客户端时,这是有好处的。

SET SQL_LOG_BIN = 0 | 1

如果设置为0,则客户端的二进制日志中不会记录日志。客户端必须拥有SUPER 权限来设置此选项。

SET SQL_LOG_OFF = 0 | 1

如果设置为1, 则此客户端的总查询日志中不会记录日志。客户端必须拥有权限来设置此选项。

SET SQL_LOG_UPDATE = 0 | 1

不赞成使用本变量。本变量本映射到SQL_LOG_BIN。

SET SQL_QUOTE_SHOW_CREATE 0 | 1

如果设置为1,则SHOW CREATE TABLE 会对表和列到名称加引号。如果设置为0,则加引号操作被禁用。默认情况下,本选项被启用,因此对于含有需要加引号的名称的表,复制操作起作用。

SET SQL_SAFE_UPDATES = 0 | 1

如果设置为1,则MySQL不会执行没有WHERE子句的UPDATE或DELETE语句。

SET SQL_SELECT_LIMIT = value | DEFAULT

从SELECT语句返回的记录的最大数目。对于一个新连接,默认值时“unlimited"。如果更改了限值,可以使用SQL_SELECT_LIMIT = DEFAULT来恢复默认值。如果SELECT有一个LIMIT子句,则LIMIT优先于SQL_SELECT_LIMIT值。SQL_SELECT_LIMIT不适用于在被存储的子过程中执行的SELECT语句。它也不适用于不会产生将被返回到客户端的结果集合的SELECT语句,比如,子查询中的SELECT语句,CREATE TABLE ...SELECT 和 INSERT INTO ... SELECT等(不适用的例子)。

SET SQL_WARNINGS = 0 | 1

本变量用于控制当出现警告时,单行INSERT语句是否产生一个信息字符串,默认值为0.把值设置为1,来产生一个信息字符串。

SET TIMESTAMP = timestamp_value | DEFAULT

用于为此客户端设置时间。当使用二进制日志来恢复时,本语句用于得到原始的时间标记。timestamp_value应为一个Unix时间标记,而不是MySQL时间标记。

SET UNIQUE_CHECKS = 0 | 1

如果设置为1(默认),则会对InnoDB表中的二级索引执行唯一性检查。如果设置为0,则对于被插入到InnoDB的插入缓冲器中的索引登录项,不执行唯一性检查。如果可以肯定数据不违反唯一性要求,则可以把此值设定为0,以加快向InnoDB导入大型表的速度。


※SHOW BINLOG EVENTS [IN logname] [FROM pos] [LIMIT offset, rows]

如果该命令的执行不带选项,那么它返回当前激活的日志文件的全部内容。选项允许对其他日志文件的说明,或者是限制输出。请注意,该命令也可以用来读取外部MySQL服务器的日志文件。


※SHOW CHARACTER SET [LIKE pattern]

从MySQL4.1版本开始,SHOW CHARACTER SET命令返回一个所有可支持的字符集和它们默认的排序方式的清单。


※SHOW COLLATION [LIKE pattern]

 从MySQL4.1开始,SHOW COLLATION命令返回一个所有可支持的排序方式的清单。


※SHOW COLUMN TYPES

现在没有这个命令了。


※SHOW [FULL] COLUMNS FROM tablename

[ FROM databasename ] [ LIKE pattern]

以下四个命令是等效的:

  • SHOW COLUMNS FROM tblname
  • SHOW FIELDS FROM tblname
  • DESC[RIBLE] tblname
  • EXPLAIN tblname

mysql学习笔记_第97张图片


※SHOW CREATE DATABASE dbname

从MySQL4.1版本开始,此命令显示数据库创建时的命令


※SHOW CREATE FUNCTIOIN/PROCEFURE name


※SHOW CREATE TABLE tblname

显示建表语句。在命令的结果里,所有的对象名都被括在两个反引号之间,如`tblname`, `columnname`。加入不需要这样的结果,需要提前执行 SET SQL_QUOTE_SHOW_CREATE = 0 命令。


※SHOW CREATE VIEW name


※SHOW DATABASES [LIKE pattern]

SHOW DATABASES命令返回一个用户可以访问的所有数据库的清单。该清单可以通过带有通配符"_" 和 "%"的搜索模式进行过滤。同样的信息也可以通过使用外部程序mysqlshow来获得。

对于具有Show Databases权限的用户,SHOW DTABASES命令返回一个所有数据库的清单,包括那些用户不能够访问的数据库。


※SHOW [STORAGE] ENGINES

从MySQL4.1版本开始,SHOW ENGINES命令显示所有数据表引擎的清单(MyISAM, InnoDB等),包括驱动器是否由当前的MySQL版本支持的信息。


※SHOW ERRORS [LIMIT [offset,] count]

SHOW COUNT(*) ERRORS

相关系统变量:max_error_count 和 error_count。

返回的是上一个执行的SQL命令所触发的出错清单(一条命令可以由多个错误出现???)。


※SHOW FIELDS

SHOW COLUMNS的同义词。


※SHOW FUNCTION STATUS [LIKE 'pattern']

从MySQL5.0版开始,该命令返回一个所有函数(SP)的清单。该清单覆盖所有的数据库。作为可选项,该清单可以减少到所有名字满足搜索模式的函数(允许使用SQL的通配符"_"和 "%")。可以使用SHOW PROCEDURE STATUS命令来显示所有程序的清单。


※SHOW GRANTS FOR user@host

SHOW GRANTS命令显示对一个特定用户的所有访问权限的清单。user和host必须要必要准确定义,因为这些字符串要存储在各种mysql访问数据表中。不允许使用通配符。


※SHOW INDEX FROM table

返回一个关于给定数据表的所有索引信息的数据表。


※SHOW INNODB STATUS

没有这个命令!


※SHOW KEYS FROM tblname

SHOW INDEX 的同义词。


※SHOW [BDB] LOGS

该命令显示当前使用的BDB日志文件是哪一个。如果当前没有使用BDB数据表,那么该命令就不返回结果。


※SHOW MASTER STATUS

该命令用来显示哪一个是当前的日志文件,它在这个文件中的位置以及哪些数据库是在日志之外(配置设置为binlog-do-db和binlog-ignore-db)。它只能够在镜像系统的主控计算机上执行。


※SHOW PRIVILEGES

从MySQL4.1版本开始,该命令返回一个所有可支持的权限清单,并具有简单的描述。


※SHOW PROCEDURE STATUS [LIKE 'pattern']


※SHOW [FULL] PROCESSLIST

该命令返回一个MySQL服务器里运行的所有线程(子处理过程)的清单。如果赋予了PROCESS权限,那么所有的线程都被显示出来,否则,只是显示用户的线程。

选项FULL的 作用是,对于每一个线程,最近执行的命令的全部文本都会被显示。没有这个选项,只有前100个字符会被显示出来。

也可是使用外部命令mysqladmin来显示进程清单。


※SHOW SLAVE HOSTS

该命令返回一个复制主数据库的所有从属服务器清单。改命令只能够用于镜像机制系统中的主控计算机上。它只是在从属服务器上起作用,对于这些从属服务器来说,主机名字在配置文件中由明确规定,其格式为report-host = hostname。


※SHOW SLAVE STATUS

该命令提供了镜像机制系统中的状态信息,包括显示有关文件master.info的所有信息。该命令只能够用于镜像机制系统中的从属计算机上。


※SHOW [GLOBAL | SESSIOIN] STATUS [LIKE 'pattern' | WHERE expr]

该命令返回一个各种MySQL状态变量的清单,这些变量提供了有关MySQL当前状态的信息。这些相同的信息也可以由外部程序mysqladmin 来显示。对所有状态变量的描述请参考MySQL文档:https://dev.mysql.com/doc/refman/5.7/en/show-status.html 

※SHOW TABLE STATUS [FROM database] [LIKE pattern]

此命令返回有关当前活跃的所有数据表或指定的数据库的信息:数据表的类型,记录的数目,平均记录长度,Create_time,Update_time等。这些相同的信息也可以由外部程序mysqladmin来显示。允许使用通配符"_"和"%".


※SHOW TABLES [FROM database] [LIKE pattern]

此命令返回一个当前或指定数据库中的所有数据表和Views的清单。此清单也可以使用外部程序mysqlshow显示。


※SHOW [options] VARIABLES [LIKE pattern]

返回一份非常长的系统变量清单。可以在启动MySQL的时候设置这种变量,或者是在启动以后用SET命令来设置。变量清单也可以使用外部程序mysqladmin来显示。

options:在这里可以规定GLOBAL选项或者是SESSION选项。GLOBAL选项的作用是显示在全局有效的默认值。而SESSION选项意味着只显示对当前连接有效的值。默认设置是SESSION选项

对各个系统变量的解释参见MySQL文档:https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html


※SHOW WARNINGS [LIMIT [offset,] count]

SHOW COUNT(*) WARNINGS

显示上一条执行的SQL命令中出现的:警告,错误,提示等。(注意,不止显示警告!)


※SLAVE START / STOP [IO_THREAD | SQL_THREAD]

这些命令开始或结束镜像机制。它们只能在镜像机制系统中的从属计算机上执行。

默认情况下,两个线程启动用于复制:IO线程(把二进制日志数据从主控计算机复制到从属计算机)和SQL线程(执行日志文件的SQL命令)。使用IO_THREAD或SQL_THREAD的选项说明,这两个线程可以独立地启动或停止(只是在调试时这样做才有意义)。


※START TRANSACTION


※TRUNCATE [TABLE] tablename

TRUNCATE 命令和不带WHERE子句的DELETE命令有些类似,但也有区别.具体可用help truncate table查看。作用是删除数据表中的所有记录。完成这一操作的方式是先删除整个数据表,然后在重新创建它。(这样做比逐条删除记录快许多)


※UNLOCK TABLE[S]

此命令删除所有用户设置的LOCK选项。该命令对所有的数据库有效(如,与哪一个数据库是当前数据库没有关系).


※UDPATE [updateoptions] tablename SET col1=value1, col2=value2 ...

[WHERE condition]

[ORDER BY columns]

[limit maxrecords]

mysql学习笔记_第98张图片


※UPDATE [updateoptions] table1, table2, table3

SET table1.col1=table2.col2 ...

[WHERE condition] [ ORDER BY columns] [LIMIT maxrecords]

从MySQL4.0版本开始,UPDATE命令可以包括不止一个数据表。这个语法要求把本次修改操作所涉及的所有数据表列列在关键字UPDATE的后面。但只有在SET子句里被赋值的数据列(数据表)会被修改。数据表之间的关联关系由WHERE子句来设置。


※USE databasename

USE命令把给定数据库设置为当前MySQL连接的默认数据库。在这条连接被关闭之前(或者是在执行下一条USE命令之前),后续的SQL 命令将默认地以给定数据库databasename里的数据表作为操作对象。



 

7, SQL函数指南

7.1, 算术函数

 mysql学习笔记_第99张图片

TRUNCATE(x,y):将x保留到小数点后y位,其余的直接删除掉。比如:

  • TRUNCATE(11.129,2) //结果位11.12
  • TRUNCATE(111.129,0) // 111
  • TRAUNCATE(111.129,-1) //110
  • TRUNCATE(111.129,-2) //100

一般说来,如果用户提供的参数是无效或是非法的,这些函数都将返回NULL。


7.2, 比较函数、测试函数、分支函数

mysql学习笔记_第100张图片

说明一点:STRCMP("a", 97); //返回的是1,此时比较的是"a"和"9"的大小顺序!

mysql学习笔记_第101张图片


7.3, 类型转换(投射)

参看:https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html

※CAST(x AS type)

把x转化为指定类型。其中的type只能取以下类型:

o BINARY[(N)]

o CHAR[(N)]

o DATE

o DATETIME

o DECIMAL[(M[,D])]

o JSON (added in MySQL 5.7.8)

o SIGNED [INTEGER]

o TIME

o UNSIGNED [INTEGER]

※CONVERT(x, type)

和CAST()的作用一样。

※CONVERT(s USING cs)

在字符集cs中表示字符s,从MySQL4.1版本开始。

※BINARY expr

将expr转化为二进制字符串,在字符串比较时时逐字节的比较而不是逐个字符的比较。这将区分字母的大小写,以及字符串后面的空白。见下面例子:

  • SELECT 'A' = 'a' // 返回1
  • SELECT BINARY 'A' = 'a' //返回0
  • SELECT 'a' = 'a     ' / /返回1
  • SELECT BINARY 'a' = 'a   ' // 返回0

下面三个表达式效果相同,都可以将一个字符串expr转化为二进制字符串。

  • BINARY expr
  • CAST(expr AS BINARY)
  • CONVERT(expr USING BINARY)

 


7.4,字符串处理 p620 p687

mysql学习笔记_第102张图片

mysql学习笔记_第103张图片

mysql学习笔记_第104张图片

mysql学习笔记_第105张图片


7.5, 日期和时间函数

mysql学习笔记_第106张图片

DATE_FORMAT(datetime, format)

FROM_UNIXTIME(ts[,format])

其中的format的格式如下:

mysql学习笔记_第107张图片

mysql学习笔记_第108张图片

其他一些日期和时间函数:

mysql学习笔记_第109张图片

mysql学习笔记_第110张图片

mysql学习笔记_第111张图片

mysql学习笔记_第112张图片


7.6,GROUP BY 函数

以下函数经常用于如下语句:

SELECT AVG(field) FROM tbname WHERE ... GROUP BY ...

mysql学习笔记_第113张图片


7.7,其他函数

mysql学习笔记_第114张图片

关于LOAD_FILE()函数:如果一直返回NULL,则:

SHOW VARIABLES LIKE "secure_file_priv";是否为null

mysql 新版本下secure-file-priv字段 : secure-file-priv参数是用来限制LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE()传到哪个指定目录的。

secure_file_priv的值为null ,表示限制mysqld 不允许导入|导出

当secure_file_priv的值为/tmp/ ,表示限制mysqld 的导入|导出只能发生在/tmp/目录下

当secure_file_priv的值没有具体值时,表示不对mysqld 的导入|导出做限制

解决方法是在配置文件my.ini(mysql.cnf)中[mysqld]下加入

secure_file_priv =

然后保存重启MySQL即可。

mysql学习笔记_第115张图片

关于BENCHMARK(n, expr)函数用法:

SELECT BENCHMARK(100000, MD5("hello world"));

mysql学习笔记_第116张图片

 

返回值都是0,执行时间如红框所示。报告的时间是客户端的经过时间,不是在服务器端的CPU时间。

关于FOUND_ROWS()函数:

此函数返回上一条SELECT命令的返回的总结果条目。如果在LIMIT语句中使用SQL_CALC_FOUND_ROWS选项,则返回的是不用LIMIT时的总数目。否则返回LIMIT的条数。

同样对于INSERT / UPDATE / DELETE 命令也有一个函数ROW_COUNT()来表明上一条命令受影响的条数。

mysql学习笔记_第117张图片


7.8,GIS数据类型与GIS函数 p631

mysql学习笔记_第118张图片

mysql学习笔记_第119张图片

mysql学习笔记_第120张图片


7.9,常用的函数汇总

一、数学函数
ABS(x)   返回x的绝对值

BIN(x)   返回x的二进制(OCT返回八进制,HEX返回十六进制)
CEILING(x)   返回大于x的最小整数值
EXP(x)   返回值e(自然对数的底)的x次方
FLOOR(x)   返回小于x的最大整数值
GREATEST(x1,x2,...,xn)返回集合中最大的值
LEAST(x1,x2,...,xn)      返回集合中最小的值
LN(x)                    返回x的自然对数
LOG(x,y)返回x的以y为底的对数
MOD(x,y)                 返回x/y的模(余数)
PI()返回pi的值(圆周率)
RAND()返回0到1内的随机值,可以通过提供一个参数(种子)使RAND()随机数生成器生成一个指定的值。
ROUND(x,y)返回参数x的四舍五入的有y位小数的值
SIGN(x) 返回代表数字x的符号的值
SQRT(x) 返回一个数的平方根
TRUNCATE(x,y)            返回数字x截短为y位小数的结果

二、聚合函数(常用于GROUP BY从句的SELECT查询中)
AVG(col)返回指定列的平均值
COUNT(col)返回指定列中非NULL值的个数
MIN(col)返回指定列的最小值
MAX(col)返回指定列的最大值
SUM(col)返回指定列的所有值之和
GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果

三、字符串函数
ASCII(char)返回字符的ASCII码值
BIT_LENGTH(str)返回字符串的比特长度
CONCAT(s1,s2...,sn)将s1,s2...,sn连接成字符串
CONCAT_WS(sep,s1,s2...,sn)将s1,s2...,sn连接成字符串,并用sep字符间隔
INSERT(str,x,y,instr) 将字符串str从第x位置开始,y个字符长的子串替换为字符串instr,返回结果
FIND_IN_SET(str,list)分析逗号分隔的list列表,如果发现str,返回str在list中的位置
LCASE(str)或LOWER(str) 返回将字符串str中所有字符改变为小写后的结果
LEFT(str,x)返回字符串str中最左边的x个字符
LENGTH(s)返回字符串str中的字符数
LTRIM(str) 从字符串str中切掉开头的空格
POSITION(substr,str) 返回子串substr在字符串str中第一次出现的位置
QUOTE(str) 用反斜杠转义str中的单引号
REPEAT(str,srchstr,rplcstr)返回字符串str重复x次的结果
REVERSE(str) 返回颠倒字符串str的结果
RIGHT(str,x) 返回字符串str中最右边的x个字符
RTRIM(str) 返回字符串str尾部的空格
STRCMP(s1,s2)比较字符串s1和s2
TRIM(str)去除字符串首部和尾部的所有空格
UCASE(str)或UPPER(str) 返回将字符串str中所有字符转变为大写后的结果

四、日期和时间函数
CURDATE()或CURRENT_DATE() 返回当前的日期
CURTIME()或CURRENT_TIME() 返回当前的时间
DATE_ADD(date,INTERVAL int keyword)返回日期date加上间隔时间int的结果(int必须按照关键字进行格式化),如:SELECTDATE_ADD(CURRENT_DATE,INTERVAL 6 MONTH);
DATE_FORMAT(date,fmt)  依照指定的fmt格式格式化日期date值
DATE_SUB(date,INTERVAL int keyword)返回日期date加上间隔时间int的结果(int必须按照关键字进行格式化),如:SELECTDATE_SUB(CURRENT_DATE,INTERVAL 6 MONTH);
DAYOFWEEK(date)   返回date所代表的一星期中的第几天(1~7)
DAYOFMONTH(date)  返回date是一个月的第几天(1~31)
DAYOFYEAR(date)   返回date是一年的第几天(1~366)
DAYNAME(date)   返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
FROM_UNIXTIME(ts,fmt)  根据指定的fmt格式,格式化UNIX时间戳ts
HOUR(time)   返回time的小时值(0~23)
MINUTE(time)   返回time的分钟值(0~59)
MONTH(date)   返回date的月份值(1~12)
MONTHNAME(date)   返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
NOW()    返回当前的日期和时间
QUARTER(date)   返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);
WEEK(date)   返回日期date为一年中第几周(0~53)
YEAR(date)   返回日期date的年份(1000~9999)
一些示例:
获取当前系统时间:SELECT FROM_UNIXTIME(UNIX_TIMESTAMP());
SELECT EXTRACT(YEAR_MONTH FROM CURRENT_DATE);
SELECT EXTRACT(DAY_SECOND FROM CURRENT_DATE);
SELECT EXTRACT(HOUR_MINUTE FROM CURRENT_DATE);
返回两个日期值之间的差值(月数):SELECT PERIOD_DIFF(200302,199802);
在Mysql中计算年龄:
SELECT DATE_FORMAT(FROM_DAYS(TO_DAYS(NOW())-TO_DAYS(birthday)),'%Y')+0 AS age FROM employee;
这样,如果Brithday是未来的年月日的话,计算结果为0。
下面的SQL语句计算员工的绝对年龄,即当Birthday是未来的日期时,将得到负值。
SELECT DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(birthday, '%Y') -(DATE_FORMAT(NOW(), '00-%m-%d')
五、加密函数
AES_ENCRYPT(str,key)  返回用密钥key对字符串str利用高级加密标准算法加密后的结果,调用AES_ENCRYPT的结果是一个二进制字符串,以BLOB类型存储
AES_DECRYPT(str,key)  返回用密钥key对字符串str利用高级加密标准算法解密后的结果
DECODE(str,key)   使用key作为密钥解密加密字符串str
ENCRYPT(str,salt)   使用UNIXcrypt()函数,用关键词salt(一个可以惟一确定口令的字符串,就像钥匙一样)加密字符串str
ENCODE(str,key)   使用key作为密钥加密字符串str,调用ENCODE()的结果是一个二进制字符串,它以BLOB类型存储
MD5()    计算字符串str的MD5校验和
PASSWORD(str)   返回字符串str的加密版本,这个加密过程是不可逆转的,和UNIX密码加密过程使用不同的算法。
SHA()    计算字符串str的安全散列算法(SHA)校验和
示例:
SELECT ENCRYPT('root','salt');
SELECT ENCODE('xufeng','key');
SELECT DECODE(ENCODE('xufeng','key'),'key');#加解密放在一起
SELECT AES_ENCRYPT('root','key');
SELECT AES_DECRYPT(AES_ENCRYPT('root','key'),'key');
SELECT MD5('123456');
SELECT SHA('123456');

六、控制流函数
MySQL有4个函数是用来进行条件操作的,这些函数可以实现SQL的条件逻辑,允许开发者将一些应用程序业务逻辑转换到数据库后台。
MySQL控制流函数:
CASE WHEN[test1] THEN [result1]...ELSE [default] END如果testN是真,则返回resultN,否则返回default
CASE [test] WHEN[val1] THEN [result]...ELSE [default]END  如果test和valN相等,则返回resultN,否则返回default
IF(test,t,f)   如果test是真,返回t;否则返回f
IFNULL(arg1,arg2) 如果arg1不是空,返回arg1,否则返回arg2
NULLIF(arg1,arg2) 如果arg1=arg2返回NULL;否则返回arg1
这些函数的第一个是IFNULL(),它有两个参数,并且对第一个参数进行判断。如果第一个参数不是NULL,函数就会向调用者返回第一个参数;如果是NULL,将返回第二个参数。
如:SELECT IFNULL(1,2), IFNULL(NULL,10),IFNULL(4*NULL,'false');
NULLIF()函数将会检验提供的两个参数是否相等,如果相等,则返回NULL,如果不相等,就返回第一个参数。
如:SELECT NULLIF(1,1),NULLIF('A','B'),NULLIF(2+3,4+1);
和许多脚本语言提供的IF()函数一样,MySQL的IF()函数也可以建立一个简单的条件测试,这个函数有三个参数,第一个是要被判断的表达式,如果表达式为真,IF()将会返回第二个参数,如果为假,IF()将会返回第三个参数。
如:SELECTIF(1<10,2,3),IF(56>100,'true','false');
IF()函数在只有两种可能结果时才适合使用。然而,在现实世界中,我们可能发现在条件测试中会需要多个分支。在这种情况下,MySQL提供了CASE函数,它和PHP及Perl语言的switch-case条件例程一样。
CASE函数的格式有些复杂,通常如下所示:
CASE [expression to be evaluated]
WHEN [val 1] THEN [result 1]
WHEN [val 2] THEN [result 2]
WHEN [val 3] THEN [result 3]
......
WHEN [val n] THEN [result n]
ELSE [default result]
END
这里,第一个参数是要被判断的值或表达式,接下来的是一系列的WHEN-THEN块,每一块的第一个参数指定要比较的值,如果为真,就返回结果。所有的WHEN-THEN块将以ELSE块结束,当END结束了所有外部的CASE块时,如果前面的每一个块都不匹配就会返回ELSE块指定的默认结果。如果没有指定ELSE块,而且所有的WHEN-THEN比较都不是真,MySQL将会返回NULL。
CASE函数还有另外一种句法,有时使用起来非常方便,如下:
CASE
WHEN [conditional test 1] THEN [result 1]
WHEN [conditional test 2] THEN [result 2]
ELSE [default result]
END
这种条件下,返回的结果取决于相应的条件测试是否为真。
示例:
mysql>SELECT CASE 'green'
     WHEN 'red' THEN 'stop'
     WHEN 'green' THEN 'go' END;
SELECT CASE 9 WHEN 1 THEN 'a' WHEN 2 THEN 'b' ELSE 'N/A' END;
SELECT CASE WHEN (2+2)=4 THEN 'OK' WHEN(2+2)<>4 THEN 'not OK' END ASSTATUS;
SELECT Name,IF((IsActive = 1),'已激活','未激活') AS RESULT FROMUserLoginInfo;
SELECT fname,lname,(math+sci+lit) AS total,
CASE WHEN (math+sci+lit) < 50 THEN 'D'
WHEN (math+sci+lit) BETWEEN 50 AND 150 THEN 'C'
WHEN (math+sci+lit) BETWEEN 151 AND 250 THEN 'B'
ELSE 'A' END
AS grade FROM marks;
SELECT IF(ENCRYPT('sue','ts')=upass,'allow','deny') AS LoginResultFROM users WHERE uname = 'sue';#一个登陆验证

七、格式化函数
DATE_FORMAT(date,fmt)  依照字符串fmt格式化日期date值
FORMAT(x,y)   把x格式化为以逗号隔开的数字序列,y是结果的小数位数
INET_ATON(ip)   返回IP地址的数字表示
INET_NTOA(num)   返回数字所代表的IP地址
TIME_FORMAT(time,fmt)  依照字符串fmt格式化时间time值
其中最简单的是FORMAT()函数,它可以把大的数值格式化为以逗号间隔的易读的序列。
示例:
SELECT FORMAT(34234.34323432,3);
SELECT DATE_FORMAT(NOW(),'%W,%D %M %Y %r');
SELECT DATE_FORMAT(NOW(),'%Y-%m-%d');
SELECT DATE_FORMAT(19990330,'%Y-%m-%d');
SELECT DATE_FORMAT(NOW(),'%h:%i %p');
SELECT INET_ATON('10.122.89.47');
SELECT INET_NTOA(175790383);

八、类型转化函数
为了进行数据类型转化,MySQL提供了CAST()函数,它可以把一个值转化为指定的数据类型。类型有:BINARY,CHAR,DATE,TIME,DATETIME,SIGNED,UNSIGNED
示例:
SELECT CAST(NOW() AS SIGNED INTEGER),CURDATE()+0;
SELECT 'f'=BINARY 'F','f'=CAST('F' AS BINARY);

九、系统信息函数
DATABASE()   返回当前数据库名
BENCHMARK(count,expr)  将表达式expr重复运行count次
CONNECTION_ID()   返回当前客户的连接ID
FOUND_ROWS()   返回最后一个SELECT查询进行检索的总行数
USER()或SYSTEM_USER()  返回当前登陆用户名
VERSION()   返回MySQL服务器的版本
示例:
SELECT DATABASE(),VERSION(),USER();
SELECTBENCHMARK(9999999,LOG(RAND()*PI()));#该例中,MySQL计算LOG(RAND()*PI())表达式9999999次。

 

第二章:MySQL工具和选项

 

第三章:MySQL API应用指南

六,附录

第一章

你可能感兴趣的:(mysql学习笔记)