微信搜索关注公众号【三朝猿老】,第一时间获取更多内容。
说明:本文所使用的书籍《MySQL必知必会》[英] Ben Forta 著,刘晓霞 钟鸣 译
本文中 tbl_name 为数据库表名称,db_name 为数据库名称,col_name 为字段名称。
创建时设置自动增量:
CREATE TABLE tbl_name
( id int PRIMARY KEY AUTO_INCREMENT,
...
);
分析:上述代码创建表,设置表主键id自动增长,默认自动增长的起始值为1开始。
修改表中列为自动增量:
ALTER TABLE 表名 MODIFY 字段名 字段类型 AUTO_INCREMENT;
修改后从下一条记录开始自动增长。如果想让原来的自动增长就得复制现有表的结构(无id),添加id并加上AUTO_INCREMENT
,然后通过循环,添加n条空记录,然后对应先前表的id,依次插入数据。
注意:
AUTO_INCREMENT=1001
,表示从1001开始自增增量,默认自动变量从1开始。last_insert_id()
函数获得这个值。在命令行(CMD)里,进入MySQL安装根目录下的bin目录下
比如:C:\Program Files\MySQL\MySQL Server 5.5\bin
进入MySQL的bin路径:
cd "C:\Program Files\MySQL\MySQL Server 5.5\bin"
注意:命令行中不加分号。以下导出都在bin目录下进行。
(1)导出数据库:
mysqldump -uroot -p 数据库名 > 导出文件的路径\导出文件名.sql
注意:这里最后不加分号。按回车后,输入MySQL密码,验证后开始导出整个数据库和数据。
(2)使用条件导出数据库:
mysqldump -uroot -p --where='id < 5' 数据库名 > 导出文件的路径\导出文件名.sql
(3)只导出一张表:
mysqldump -uroot -p 数据库名 表名 > 导出文件的路径\导出文件名.sql
特别注意
在CMD命令行里输入的路径如果有空格,可用如下解决方法:
给路径名上加上双引号(" ")然后cd执行即可;
用缩写。比如c:\Program Files缩写为c:\Progra~1;
采用8个字符缩写,即写头六个字母(略去空白),另加波浪号和1,首字母不足六个字母,略去空白,用第二个词的字母,凑成六个。例如:
- "Documents and Settings“ --> Docume~1
- “Local Settings” --> LOCALS~1
如果多个文件前6字符一样怎么办?看看如下例子:
假设下面是你的C盘根目录中的文件夹:
Program Files
Progra file
Progra zhang
则三个目录分别表示为:C:\Progra~1; C:\Progra~2; C:\Progra~3;绕过去,创建一个镜像。
例如在CMD中输入
subst w: "C:\Documents and Settings"
,然后就可以直接用w:\替代C:\Documents and Settings了。
首先创建数据库,然后在use数据库后运行*.sql
的脚本文件,即执行如下代码:
source 脚本文件路径/script.sql
注意:文件路径层次的分隔使用/
,如下形式:
source C:/Users/Eric/Desktop/create.sql
3.1 常用show语句(< = >表示等价关系)
-- 显示所有数据库
show databases
-- 显示所有表格(首先应use 数据库)
show tables
-- 显示表的列详细信息(字段名、数据类型、是否运行NULL、键信息、默认值以及其他信息)
show columns from tbl_name < = > describe tbl_name
-- 显示创建数据库时的详细信息
show create database db_name
-- 显示创建表时的详细信息
show create table tbl_name
-- 显示授权用户的安全权限
show grants
3.2 完整show用法
SHOW {BINARY | MASTER} LOGS
SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]
SHOW CHARACTER SET [like_or_where]
SHOW COLLATION [like_or_where]
SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [like_or_where]★
SHOW CREATE DATABASE db_name★
SHOW CREATE EVENT event_name
SHOW CREATE FUNCTION func_name
SHOW CREATE PROCEDURE proc_name★
SHOW CREATE TABLE tbl_name★
SHOW CREATE TRIGGER trigger_name★
SHOW CREATE VIEW view_name★
SHOW DATABASES [like_or_where]
SHOW ENGINE engine_name {STATUS | MUTEX}
SHOW [STORAGE] ENGINES
SHOW ERRORS [LIMIT [offset,] row_count]
SHOW EVENTS
SHOW FUNCTION CODE func_name
SHOW FUNCTION STATUS [like_or_where]
SHOW GRANTS FOR user
SHOW INDEX FROM tbl_name [FROM db_name]
SHOW MASTER STATUS
SHOW OPEN TABLES [FROM db_name] [like_or_where]
SHOW PLUGINS
SHOW PROCEDURE CODE proc_name★
SHOW PROCEDURE STATUS [like_or_where]
SHOW PRIVILEGES
SHOW [FULL] PROCESSLIST
SHOW PROFILE [types] [FOR QUERY n] [OFFSET n] [LIMIT n]
SHOW PROFILES
SHOW RELAYLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]
SHOW SLAVE HOSTS
SHOW SLAVE STATUS [FOR CHANNEL channel]
SHOW [GLOBAL | SESSION] STATUS [like_or_where]
SHOW TABLE STATUS [FROM db_name] [like_or_where]
SHOW [FULL] TABLES [FROM db_name] [like_or_where]★
SHOW TRIGGERS [FROM db_name] [like_or_where]★
SHOW [GLOBAL | SESSION] VARIABLES [like_or_where]
SHOW WARNINGS [LIMIT [offset,] row_count]
like_or_where:
LIKE 'pattern'
| WHERE expr
使用方法:
CREATE TABLE tbl_name
( ...
...
) ENGINE=InnoDB;
CREATE TABLE tbl_name
( ...
...
) ENGINE=MyISAM;
注意:引擎类型可以混用,即不同的表可以使用不用的引擎类型。但是外键不能跨引擎,也就是使用一个引擎的表不能引用使用不同引擎表的外键。
alter table old_tbl_name rename to new_tbl_name;
ALTER TABLE tbl_name ADD col_name char(20);
-- 修改字段名称
alter table tbl_name change old_col_name new_col_name type;
-- 修改字段类型
ALTER TABLE tbl_name MODIFY col_name char(20);
ALTER TABLE tbl_name DROP COLUMN col_name;
比较常用的Alter用法是对表添加约束,主要约束有主键约束、外键约束、check约束、unique约束、not null约束。
ALTER TABLE tbl_name1 ADD CONSTRAINT pk_name PRIMARY KEY(col_name, ...);
ALTER TABLE tbl_name1 ADD CONSTRAINT fk_tblname1_tblname2 FOREIGN KEY (col_name1) REFERENCES tbl_name2 (col_name2);
-- 可以在创建表时同时创建外键约束
CREATE TABLE selectcourse
(
sno char(8),
cno char(10),
score int not null default 0,
constraint pk_sc primary key (sno, cno), -- 主键
constraint fk_sc_s foreign key(sno) references students(sno),
constraint fk_sc_c foreign key(cno) references courses(cno)
);
ALTER TABLE student ADD CONSTRAINT ck_student_sex CHECK(sex = '男' or sex = '女');
ALTER TABLE tbl_name ADD CONSTRAINT uq_name UNIQUE(col_name);
ALTER TABLE tbl_name MODIFY col_name NOT NULL;
-- 取消not null约束
ALTER TABLE tbl_name MODIFY col_name NULL;
ALTER TABLE tbl_name DROP CONSTRAINT 约束名称;
6.1 LIMIT n
用法
SELECT col_name FROM tbl_name
LIMIT 5;
其中LIMIT 5
指示MySQL从行0开始,一共返回5行的数据。
6.2 LIMIT m, n
用法
SELECT col_name FROM tbl_name
LIMIT 5,3;
其中LIMIT 5,3
表示为MySQL从行5开始,一共返回3行数据。
注意:检索出来的第一行的行号为行0而不是行1。如LIMIT 1,1
返回的其实是检索结果中的第二行数据,但是第二行数据的行号为行1。
6.3 LIMIT n OFFSET m
用法
为了可读性更强,可以使用如下代码表示从行号5开始返回3行数据:
LIMIT 3 OFFSET 5
其中的OFFSET 5
表示为起始行号为5,3表示为返回的数据行数为3。
正则表达式的作用是匹配文本,将一个模式(pattern,也即正则表达式)与一个文本串(text)比较,如果text中含有此pattern,则返回1,否则返回0。
可利用此性质在where子句中使用正则表达式获得相应的匹配数据行。
用法:
REGEXP '正则表达式'
,表示利用正则表达式进行匹配。
SELECT col_name
FROM tbl_name
WHERE col_name REGEXP '1000'
分析:上述语句中的REGEXP '1000'
表示匹配正则表达式1000
,如果相应列值内容中含有1000
子串,则返回此数据记录。
SELECT col_name
FROM tbl_name
WHERE col_name REGEXP '.000'
分析:上述语句中的REGEXP '.000'
表示匹配正则表达式.000
,其中的.
表示匹配任意一个字符,所以如果相应列值内容中含有*000
子串(星号代表任意字符),则返回此数据记录。
LIKE和 REGEXP 重要区别:
- LIKE匹配整个串。如果被匹配的文本在列值中出现,LIKE不会找到它,相应的行也不会被返回。即如果LIKE后的匹配串中如果不带有通配符( % 或 _ ),则不会返回任何结果。
- REGEXP匹配子串。如果被匹配的文本在列值中出现,REGEXP会找到它并将相应的行返回。
现在假如数据库中有表mytable,表中有id号为1000的数据记录,则下列代码会有不同的返回结果:
-- 无返回结果 SELECT * FROM mytable WHERE id LIKE '1000'; -- 有返回id为1000的数据行 SELECT * FROM mytable WHERE id REGEXP '1000';
注意:正则表达式默认匹配不区分大小写,若要区分大小写,用法为REGEXP BINARY '正则表达式'
,即在关键字REGEXP
后添加BINARY
关键字。
|
符号|
为正则表达式中的OR操作符,它表示匹配其中之一。如下代码将匹配1或2或3:
REGEXP '1|2|3'
[]
符号[]
是另一种形式的OR语句。上述代码可改写成:
REGEXP '[123]'
使用^
符号可以对字符集合进行否定,如下代码表示匹配除1、2、3外的其它任何东西:
REGEXP '[^123]'
-
定义范围集合可用来定义要匹配的一个或多个字符,也可以定义一个要匹配的集合范围,为了简化这种范围的表示,可以使用-
来定义集合的范围。如下:
REGEXP '[1-9]' < = > REGEXP '[123456789]'
REGEXP '[a-z]' -- 匹配任意字母字符(如果数据库配置为不区分大小写)
正则表达式中包含了许多特殊的字符,如上述我们学到的.
、[]
、|
、-
等,如果我们要匹配的正好是这些特殊字符,该怎么办呢?
⭐️ 为了匹配正则表达式中的特殊字符,在MySQL中必须使用\\
进行转义。多数正则表达式实现用一个\
,但在MySQL中要用两个,MySQL解释一个,正则表达式库解释另一个。
如:
REGEXP '\\.' -- 匹配.字符
REGEXP '\\|' -- 匹配|字符
REGEXP '\\\' -- 匹配\字符
空白元字符的转义:
元字符 | 说明 |
---|---|
\\f |
换页 |
\\n |
换行 |
\\r |
回车 |
\\t |
制表 |
\\v |
纵向制表 |
为了更方便的工作,可以使用预定义的字符集,称为字符类。
Posix字符类:
类 | 说明 |
---|---|
[:alpha:] |
任意字符(同[a-z][A-Z] ) |
[:lower:] |
任意小写字母(同[a-z] ) |
[:upper:] |
任意大写字母(同[A-Z] ) |
[:digit:] |
任意数字(同[0-9] ) |
[:alnum:] |
任意字母和数字(同[a-zA-Z0-9] ) |
[:cntrl:] |
ASCII控制字符(ASCII 0到31和127) |
[:punct:] |
不在[:alnum:] 和[:cntrl:] 中的其他任意字符 |
[:blank:] |
空格和制表(同[\\t] ) |
[:space:] |
包括空格在内的任意空白字符(同[\\f\\n\\r\\t\\v] ) |
[:xdigit:] |
任意十六进制数字(同[a-fA-F0-9] ) |
[:print:] |
任意可打印字符 |
[:graph:] |
与[:print:]相同,但不包括空格 |
字符类的使用,如下语句代码:
REGEXP '[[:digit:]]{3}' < = > REGEXP '[0-9]{3}' < = > REGEXP '[0-9][0-9][0-9]'
上述代码表示匹配连在一起的任意3位数。
正如上述匹配任意3位数的代码,其中就用到了匹配字符的3次出现,除了上述的[0-9]{3}
用法之外还有另一些匹配多实例的元字符。
重复元字符:
元字符 | 说明 |
---|---|
* | 匹配0个或多个 |
+ | 匹配1个或多个(同{1,}) |
? | 匹配0个或1个(同{0,1}) |
{n} | 匹配n个 |
{n,} | 匹配[n,+∞]个 |
{n,m} | 匹配[n,m]个 |
注意:使用上述重复元字符时一定要注意其涵盖的范围,如123?
和(123)?
表示不同的匹配含义。
为了匹配特定位置的文本,需要使用定位符。
定位符:
元字符 | 说明 |
---|---|
^ | 文本的开始 |
$ | 文本的结尾 |
[[:<:]] | 词的开始 |
[[:>:]] | 词的结尾 |
^
的双重用途在上述7.2中的第2个例子中,我们使用了正则表达式[^123]
用来匹配除1、2、3外的其他字符,如果我们把正则表达式改为^[123]
则表示匹配开始字符为数字1或2或3的文本。
总结:^
符号用在[]
外边,用来指串的开始处;用在[]
里边,用来否定该集合。
^
和$
匹配整个数据串,此时发挥和LIKE
一样得效果。REGEXP '^1000$' < = > LIKE '1000' -- 参照7.1 LIKE和REGEXP区别
可以在不使用数据库表的情况下用SELECT来测试正则表达式。REGEXP检查总是返回0(没有匹配)或1(匹配)。可以用带文字串的REGEXP来测试表达式,并实验他们。相应的语法如下:
SELECT 'hello, world' REGEXP '[0-9]'
上述代码显然返回0,因为文本’hello, world’中没有数字。
对于下文将要介绍的函数,可以使用如下方式进行简单的测试而不需使用具体的数据库表格,但是使用函数检索结果的列名是以函数的复杂信息显示的,为了显示简洁及便于利用检索出来的值,我们可以使用关键字AS
为新列取别名。
代码如下:
SELECT LENGTH('hello');
-- 显示结果
+----------------+
|LENGTH('hello') |
+----------------+
| 5 |
+----------------+
-- 对使用函数的新列取别名
SELECT LENGTH('hello') AS result;
-- 显示结果
+-------+
|result |
+-------+
| 5 |
+-------+
其余函数测试方法类似,不再赘述(有的不可以使用此方法测试,注意即可)。
特别注意:MySQL中串下标从1开始而不是0。
本表格中函数参数省略。
函数 | 说明 |
---|---|
Concat() |
拼接串 |
Trim() |
去掉串左右两边的空格 |
LTrim() |
去掉串左边的空格 |
RTrim() |
去掉串右边的空格 |
Upper() |
将串转换为大写 |
SubString() |
返回子串的字符 |
Locate() |
找出串的一个子串 |
Length() |
返回串的长度 |
Left() |
返回串左边length长度的字符 |
Right() |
返回串右边length长度的字符 |
Soundex() |
返回串的soundex值 |
Reverse() |
翻转串 |
Concat()
SELECT CONCAT('col_name1=',col_name1,',col_name2=',col_name2) AS result
FROM tbl_name;
//输出形式
col_name1=col_name1的内容,col_name2=col_name2的内容
Trim()
、LTrim()
、RTrim()
SELECT TRIM(col_name) AS result FROM tbl_name;
SELECT LTRIM(col_name) AS result FROM tbl_name;
SELECT RTRIM(col_name) AS result FROM tbl_name;
Upper()
SELECT UPPER(col_name) AS result FROM tbl_name;
SubString()
-- 从第n位开始,共截取m位
SELECT SUBSTRING(col_name,n,m) AS result FROM tbl_name;
-- 从第n位开始,截取到串尾
SELECT SUBSTRING(col_name,n) AS result FROM tbl_name;
Locate()
-- 如果子串在主串(表的列值)中有匹配,返回在主串中第一个字符的下标
-- 如果不匹配则返回0
SELECT LOCATE(substring, string) AS result FROM tbl_name;
-- 从主串的pos位置开始往后匹配
SELECT LOCATE(substring, string, pos) AS result FROM tbl_name;
-- 常使用方式
-- 例如:从websites表中检索出网址的url列值中以‘https://’开头的行
SELECT * FROM websites
WHERE LACATE('https://', url) = 1 -- (如果‘=0’则表示不以‘https://’开头)
类似函数:
POSITION(substring IN string)
INSTR(string, substring)
不予详细介绍。
Length()
SELECT LENGTH(col_name) AS result FROM tbl_name
Left()
、Right()
-- 返回串左边length长度的字符
SELECT LEFT(string, length) AS result FROM tbl_name;
-- 返回串右边length长度的字符
SELECT LEFT(string, length) AS result FROM tbl_name;
Soundex()
SELECT * FROM tbl_name
WHERE SOUNDEX(col_name) = SOUNDEX(string)
注意:Soundex()
函数是对串进行发音匹配比较而不是字母。
Reverse()
-- 将串翻转
SELECT REVERSE(col_name) AS result FROM tbl_name;
函数 | 说明 |
---|---|
Now() |
返回当前日期和时间 |
CurDate() |
返回当前日期 |
CurTime() |
返回当前时间 |
Date(date) |
返回日期时间的日期部分 |
Time(date) |
返回日期时间的时间部分 |
Year(date) |
返回一个日期的年份部分 |
Month(date) |
返回一个日期的月份部分 |
Day(date) |
返回一个日期的天数部分 |
Hour(time) |
返回一个时间的小时部分 |
Minute(time) |
返回一个时间的分钟部分 |
Second(time) |
返回一个时间的秒数部分 |
AddDate(date, INTERVAL expr unit) |
增加一个间隔日期 |
Date_Add(date, INTERVAL expr unit) |
增加一个间隔日期(高度灵活) |
AddTime(date, datetime) |
增加一个间隔时间 |
DateDiff(date1, date2) |
计算两个日期之差(天数) |
Date_Format(date, format) |
返回格式化日期 |
DayOfWeek(date) |
返回日期对应是星期几 |
参数说明:
AddDate()
和Date_Add()
中的参数date:起始日期或者起始时间。
expr:指定的是一个间隔值,在起始时间中增加或者减少。expr
是一个字符串,对于负值间隔,可以以"-"开头。
unit:表示的是一个单位(day/month/year),比如:加上的是1天还是一个小时。
AddTime(date, datetime)
中datetime格式如:‘1 2:3:0’(1天2小时3分钟0秒)
Date_Format(date, format)
中format可用格式:
格式 | 描述 |
---|---|
%a | 缩写星期名 |
%b | 缩写月名 |
%c | 月,数值 |
%D | 带有英文前缀的月中的天 |
%d | 月的天,数值(00-31) |
%e | 月的天,数值(0-31) |
%f | 微秒 |
%H | 小时 (00-23) |
%h | 小时 (01-12) |
%I | 小时 (01-12) |
%i | 分钟,数值(00-59) |
%j | 年的天 (001-366) |
%k | 小时 (0-23) |
%l | 小时 (1-12) |
%M | 月名 |
%m | 月,数值(00-12) |
%p | AM 或 PM |
%r | 时间,12-小时(hh:mm:ss AM 或 PM) |
%S | 秒(00-59) |
%s | 秒(00-59) |
%T | 时间, 24-小时 (hh:mm:ss) |
%U | 周 (00-53) 星期日是一周的第一天 |
%u | 周 (00-53) 星期一是一周的第一天 |
%V | 周 (01-53) 星期日是一周的第一天,与 %X 使用 |
%v | 周 (01-53) 星期一是一周的第一天,与 %x 使用 |
%W | 星期名 |
%w | 周的天 (0=星期日, 6=星期六) |
%X | 年,其中的星期日是周的第一天,4 位,与 %V 使用 |
%x | 年,其中的星期一是周的第一天,4 位,与 %v 使用 |
%Y | 年,4 位 |
%y | 年,2 位 |
例如:
本表格中函数参数省略。
函数 | 说明 |
---|---|
Abs() |
返回一个数的绝对值 |
Exp() |
返回一个数的指数 |
Sqrt() |
返回一个数的平方根 |
Mod() |
返回除操作的余数 |
Pi() |
返回圆周率 |
Rand() |
返回一个随机数 |
Sin() |
返回一个角度的正弦 |
Cos() |
返回一个角度的余弦 |
Tan() |
返回一个角度的正切 |
本表格中函数参数省略。
函数 | 说明 |
---|---|
COUNT() | 返回某列的行数 |
SUM() | 返回某列的和 |
AVG() | 返回某列的平均值 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
注意:
上表格聚集函数都自动忽略NULL值,除了如下这种特殊情况:
COUNT(col_name)
时,此函数会忽略NULL值;如:
SELECT SUM(col1*col2) AS result FROM tbl_name;
函数不仅可以使用在SELECT后面,也可以使用在WHERE子句后面进行过滤数据。
-- 检索出日期在2017-01-01到2020-01-01之间的所有行
SELECT * FROM tbl_name
WHERE DATE(col_name) = BETWEEN '2017-01-01' AND '2020-01-01'
其余用法类似,在此不再赘述。
GROUP BY
对数据分组HAVING
对分组过滤。WHERE过滤行,HAVING过滤分组,除了关键字不同,语法都是一致的。ORDER BY
对数据排序ASC
,降序排列需要使用关键字:DESC
。每个关键字只作用一列。SELECT col_name [col_name2|...]
FROM tbl_name
WHERE condition_for_row
GROUP BY col_name [col_name2|...]
HAVING condition_for_group
ORDER BY col_name [ASC|DESC]
LIMIT n [,m]
注意:顺序错误将会导致错误信息。
分为相关子查询和不相关子查询。(注意区别它们的检索的先后嵌套顺序)
不相关子查询:子查询和外部查询无关,先进行子查询,然后再进行外部查询。
相关子查询:涉及外部查询的子查询
-- 不相关子查询
SELECT col_name1
FROM tbl_name1
WHERE col_name2 IN (SELECT col_name2
FROM tbl_name2
WHERE col_name3 = 'example');
-- 相关子查询
SELECT col_name1
FROM tbl_name1 AS t1
WHERE col_name2 IN (SELECT col_name2
FROM tbl_name2 AS t2
WHERE t1.id = t2.id);
将多个表联结起来查询,有自联结、内联结(也称等值联结)、外联结(左、右)。
(1)自联结
同一张表进行连接,通常需要为表取别名。
如下代码:
SELECT col_name1, col_name2
FROM tbl_name AS t1, tbl_name AS t2
WHERE t1.id = t2.id AND p2.num = '1001'
也可以使用子查询来代替自联结查询,但通常情况下要测试一下这两种方式哪种的性能更好。
使用子查询代替自联结的代码如下:
SELECT col_name1, col_name2
FROM tbl_name
WHERE tbl_name.id = (SELECT id
FROM tbl_name
WHERE num = '1001');
(2)内联结/等值联结:
SELECT col_name1, col_name2
FROM tbl_name1 INNER JOIN tbl_name2
ON tbl_name1.id = tbl_name2.id;
-- 等值联结使用where实现
SELECT col_name1, col_name2
FROM tbl_name1 AS t1, tbl_name2 AS t2
WHERE t1.id = t2.id;
自然连接为一种特殊的等值联结,它是等值联结后消除了相同的列。
(3)外联结
-- 左外联结,左表的内容全部显示
SELECT col_name1, col_name2
FROM tbl_name1 LEFT OUTER JOIN tbl_name2
ON tbl_name1.id = tbl_name2.id;
-- 右外联结,右表的内容全部显示
SELECT col_name1, col_name2
FROM tbl_name1 RIGHT OUTER JOIN tbl_name2
ON tbl_name1.id = tbl_name2.id;
(4)使用联结和联结条件
使用关键字UNION
进行组合查,但是结果会自动去掉重复行,如果想保留重复行则需使用UNION ALL
。
其他注意地方:
首先应确保将要使用全文本搜索的表引擎类型为:MyISAM
类型。其次使用全文本搜索,必须索引被搜索的列,使用关键字FULLTEXT(col_name)
指定可以全文本索引的列,如果需要也可以指定多个列。可以在创建表时指定FULLTEXT
,也可以稍后指定,在定义之后,MySQL会自动维护该索引,在增加、更新或删除行时,索引会随之更新。
注意:不要在导入数据时使用FULLTEXT
索引,因为每次导入都会更新索引会花费更多时间,应该先导入数据,然后再修改表来定义FULLTEXT
。
对定义全文本搜索的列使用函数Match()
和Against()
进行全文本搜索,Match()用于指定被搜索的列,Against()用于指定搜索表达式。
如:
SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('example') -- 不区分搜索文本的大小写
分析:从表中可全文本搜索的列中搜索含有 ’ example ’ 值的文本,并返回数据行。MATCH(indexed_col) AGAINST('example')
语句可以使用在WHERE
子句中,也可以用作计算字段SELECT
子句中 。
注意:传递给Match()
的值必须与FULLTEXT()
定义中相同,如果指定多个列,则必须以正确次序列出它们。
使用FULLTEXT
和LIKE
的重要区别:
FULLTEXT
按文本匹配程度返回数据行(匹配等级高→匹配等级低)。全文本搜索会对每个列值数据的匹配程度生成一个匹配等级值,匹配等级越高代表匹配程度越大,全文本搜索会把匹配结果排序,较高匹配等级的先返回,因为这些数据通常恰恰就是我们需要的。FULLTEXT
数据是被索引的,因此全文本搜索速度更快。扩展查询是在使用全文本搜索时,利用查询结果再进行查询,以获得可能相关的结果。使用关键字WITH QUERY EXPANSION
进行扩展查询,如:
SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('example' WITH QUERY EXPANSION)
使用查询的扩展时,当表中的数据行越多时,返回的结果越好。
使用关键字IN BOOLEAN MODE
对文本进行布尔搜索,当没有使用FULLTEXT
索引时也可以使用布尔文本搜索,只是这时其速度极慢并且当数据量增加时性能会大大降低。
全文本布尔操作符
布尔操作符 | 说明 |
---|---|
+ | 包含,词必须存在 |
- | 排除,词必须不出现 |
> | 包含,而且增加等级值 |
< | 包含,而且减少等级制 |
() | 把词组成表达式(允许这些子表达式作为一个组被包含、排除、排列等) |
~ | 取消一个词的排序值 |
* | 词尾的截断符(也可以看作是一个通配符) |
“” | 定义一个短语(它匹配整个短语以便包含或排除这个短语,不是单个词语) |
(1)搜索匹配包含 yes 和 no 中至少一个词的行:
SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('yes no' IN BOOLEAN MODE )
(2)搜索匹配包含 yes 但不包含 no 的行:
SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('+yes -no' IN BOOLEAN MODE )
(3)搜索匹配包含 yes 和 no 中至少一个词的行,并增加 yes 的等级,降低 no 的等级
SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('>yes
(4)搜索匹配短语"yes no"的行:
SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('"yes no"' IN BOOLEAN MODE )
(5)搜索匹配词 yes 和 no,降低后者的等级:
SELECT col_name
FROM tbl_name
WHERE MATCH(indexed_col) AGAINST('+yes +(
总结:
以布尔方式,可以提供关于如下内容的细节:
全文本搜索的使用说明:
MyISAM
数据库引擎中支持全文本搜索。IN BOOLEAN MODE
。插入完整的行,不安全,如下:
insert into tbl_name values(v1, v2, ...);
编写insert语句的更安全的方法:将列名标出来,如下:
insert into customers(col1, col2, ...) values(v1, v2, ...);
如果表的定义允许,则可以在insert操作中省略某些列。省略的列必须满足以下某个条件:
如果对表中不允许null且没有默认值的列不给出值,则mysql将报错。
提高整体性能:
数据库经常被多个客户访问,insert会很耗时,而且可能降低等待处理的select语句的性能。如果数据检索是重要的,可以通过在insert和into之间添加关键字LOW_PRIORITY
,指示mysql降低insert语句的优先级。如下:
INSERT LOW_PRIORITY INTO ...
另外,LOW_PRORITY也适用于UPDATE和DELETE语句
values后面直接跟多组数据,数据间用逗号隔开
insert into customers(col1, col2, ...) values(v1, v2, ...),
(v3, v4, ...),
(v5, v6, ...);
利用insert将一条select语句的结果插入表中,即所谓的insert select语句。由一条insert和一条select语句组成,如下:
INSERT INTO customers(col1, col2, ...)
SELECT col1, col2, ...
FROM tbl_name
WHERE ...
利用已有的source表,创建新表时使用source表中的某些列创建,如下:
CREATE TABLE tbl_name AS
SELECT col1,col2, ... FROM source_table;
其中:tbl_name
是创建的新表的名称,col1
、col2
等是已存在表source中的列名称。
UPDATE还用于删除某个列的值,即清空某一列的值,使用UPDATE而不是DELETE,如下:
UPDATE tbl_name
SET col = NULL
WHERE ...
如果用UPDATE语句更新多行,并且在其中一行出错,则会回退取消整个UPDATE操作,如果要求即使发生错误也继续进行更新,可使用IGNORE关键字,如下:
UPDATE IGNORE tbl_name ...
如果想删除表中所有的行,可使用TRUNCATE TABLE
语句,它完成删除表格相同的工作,但速度更快(删除原来的并重新建一个表,而不是逐行删除表中的数据)。
重要:
为了保证UPDATE和DELETE操作不误伤(没有where或者where的效果不同于预期):
视图是虚拟的表,是几个表联结查询的动态结果。
视图不存储数据,每次查看视图时,要重新执行查询底表语句,因此大型、复杂视图性能低。
CREATE VIEW view_name AS SELECT ...
SHOW CREATE VIEW view_name;
DROP VIEW view_name;
如果指定的视图不存在,则DROP VIEW将产生一个错误。可以使用如下语句防止产生错误:
DROP VIEW IF EXISTS view_name;
create or replace view view_name
,如果视图不存在就创建,视图存在就替换。如果视图定义中有以下操作,则不能进行视图更新:
注意:一般应将视图用于检索,而非更新。对视图的增、删、改,实际是对底表数据进行操作。
存储过程,简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。
可将其视为批文件,虽然他们的作用不仅限于批处理。
优点
执行效率非常快!存储过程是在数据库的服务器端执行
简化复杂操作。因为把处理封装在容易使用的单元中;
保证了数据的完整性。不要求反复建立一系列处理步骤(防止错误);
简化对变动的管理。如果表名、列名或业务逻辑有变化,只需要修改存储过程的代码。使用它的人员甚至不需要知道这些变化(减少了数据讹误,确保了安全性);
提高性能。存储过程比单独的SQL语句要快;
代码更强更灵活。存在一些只能用在单个请求中的MySQL元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码。
缺点
CREATE PROCEDURE proc_name([ [IN|INOUT|OUT] param_name TYPE|...])
BEGIN
SELECT ...
FROM tbl_name;
END;
注意:
(1)BEGIN
和END
用来限定存储过程体。
(2)默认的MySQL分隔符为;
,但是存储过程中包含有;
,这会使存储过程中的SQL语句出现句法错误。解决办法就是临时更改命令行实用程序的语句分隔符:
DELIMITER $
CREATE PROCEDURE proc_name([ [IN|INOUT|OUT] param_name TYPE| ... ])
BEGIN
SELECT ...
FROM tbl_name;
END $
DELIMITER ;
DELEMITER $
告诉实用程序实用$
作为新的语句结束分隔符,可以看到标志存储过程结束的END定义为END $
。这样存储体内的;
可以保持不变,正确地传递给引擎,最后再恢复为原来的语句分隔符;
。除了\
之外都可定义为分隔符,\
一般用为转义符。
(3)没有参数的存储过程也不能省略()
,它就相当于一个空参的函数,调用时也要遵守这一原则。
(4)如果有参数,要明确参数类型:数据类型和输入输出类型(IN/OUT/INOUT
):
OUT
:用来从存储过程传出一个值,返回给调用者;IN
:把参数传递给存储过程;INOUT
:对存储过程传入和传出。如下代码所示:
DELIMITER $
CREATE PRODUCER proc_name(IN param1 INT, OUT param2 DECIMAL(8, 2))
BEGIN
SELECT Min(col_name)
FROM tbl_name
WHERE id = param1
INTO param2;
END $
DELIMITER ;
注意:IN类型参数和OUT类型参数的位置。
(1)SHOW PROCEDURE STATUS
列出所有存储过程,为了限制其显示某些特定的存储过程,可以用LIKE关键字指定一个过滤模式:
SHOW PROCEDURE STATUS LIKE 'proc_name'
(2)如果要获得存储过程的详细信息,可以使用SHOW语句进行显示:
SHOW CREATE PROCEDURE proc_name; -- 只给出存储过程名字
注意:此时只给出存储过程名字即可,不再加()
。
MySQL中使用关键字CALL
来执行存储过程,CALL
接收存储过程的名字以及需要传递给它的任意参数(变量)。
变量是内存中一个特定的位置,用来临时存储数据。
所有MySQL的变量都必须以@
开始。
针对上述的带参存储过程,执行语句如下:
CALL proc_name(1001, @result);
其中的1001
是传入给存储过程,变量@result
是由存储过程传出的值。
一般情况下,带有输出变量的存储过程执行后并不显示结果,而是把结果返回给你指定的变量(如上述的@result),若要显示结果,则需另外执行SELECT语句显示返回结果,如下:
SELECT @result;
DROP PROCEDURE proc_name;
此时仍然只给出存储过程名字即可,不再加()
。如果指定的存储过程不存在,则DROP PROCEDURE将产生一个错误。可以使用如下语句防止产生错误:
DROP PROCEDURE IF EXISTS proc_name;
复杂存储过程可能用到的关键字:
– : 注释
DECLARE:定义局部变量。形式如:
DECLARE variable_name TYPE
; 变量名前不用加@符号IF:条件语句,还支持ELSEIF(使用THEN), ELSE(不使用THEN)语句
COMMENT:不是必需的,但是如果给出,将在
SHOW PROCEDURE STATUS
的结果中显示,
一个实例:
考虑这个场景:有一个订单表需要获得订单合计,但需要对合计增加营业税,不过只针对某些客户。
根据场景列出存储过程中应执行的事件:
源代码如下:
-- Name:ordertotal
-- Parameters:onumber = order number
-- taxable = 0 if not taxable, 1 if taxable
-- ototal = order total variable
DELIMITER $
CREATE PROCEDURE ordertotal(IN onumber INT, IN taxable BOOLEAN,OUT ototal DECIMAL(8, 2))
COMMIT "obtain order total, optionally adding tex"
BEGIN
-- Declare variable for total
DECLARE total DECIMAL(8, 2);
-- Declare tax percentage
DECLARE taxrate INT DEFAULT 6;
-- Get the order total
SELECT Sum(item_price*quantity)
FROM orderitems
WHERE order_num = onumber
INTO total;
-- Is it taxable?
IF taxable THEN
-- Yes, so add taxrate to the total
SELECT total+(total/100*taxrate) INTO total;
END IF;
-- And finally, save to out variable
SELECT total INTO ototal;
END $
DELIMITER ;
执行存储过程并显示结果:
CALL orderototal(20005, 0, @total);
SELECT @total;
MySQL中的触发器概念,和Java中的事件监听器有点相似。当你想要某条语句在某个事件发生时自动执行,就要用到触发器了。
触发器能响应如下三类语句:DELETE、INSERT和UPDATE。
创建须知:
创建触发器时,需要给出4条信息:
创建代码如下:
CREATE TRIGGER tri_name
AFTER INSERT ON tbl_name FOR EACH ROW
SELECT 'insert success';
分析:
CREATE TRIGGER用来创建名为tri_name的新触发器。触发器可在一个操作发生之前或之后执行,这里给出了AFTER INSERT,所以此触发器将在INSERT语句成功执行后执行。这个触发器还指定FOR EACH ROW,因此代码对每个插入行执行。在这个例子中,文本“insert success”将对每个插入的行显示一次。
INSERT触发器在INSERT语句执行之前或之后执行 :
NEW
的虚拟表,访问被插入的行;NEW
的值也可以被更新(允许更改被插入的值);NEW
在INSERT执行前包含0,在INSERT被执行后包含新的自动生成值。如下代码:
CREATE TRIGGER tri_name
AFTER INSERT ON tbl_name FOR EACH ROW
SELECT NEW.col_name INTO @vari;
分析:
此代码创建一个名为tri_name的触发器,在插入新信息到tbl_name表并成功后,插入信息会保存在NEW
表中,触发器从NEW
表中取得col_name的值并赋给变量@vari
,因为从MySQL 5以后不支持触发器返回结果集,可以执行SELECT @vari
来显示它的值。
注意:
DELETE触发器在DELETE语句执行之前或之后执行:
OLD
的虚拟表,访问被删除的行;OLD
中的值全部都是只能读的,不能更新如下代码:
DELIMITER $
CREATE TRIGGER tri_name
BEFORE DELETE ON tbl_name FOR EACH ROW
BEGIN
INSERT INTO archive_table(id, name, age) VALUES(OLD.id, OLD.name, OLD.age);
END $
DELIMITER ;
分析:
在任意订单被删除前将执行此触发器。它使用一条INSERT语句将OLD中的值(要被删除的订单信息)保存到一个名为archive_table的存档表中(为实际使用这个例子,你需要建立一个和被删除信息表具有相同结构的archive_table表)。
★相对于AFTER DELETE触发器来说,使用BEFORE DELETE触发器的优点为:如果由于某种原因,订单不能存档,那么DELETE本身将被放弃,也即不再执行DELETE操作。
使用BEGIN END块的好处是触发器能容纳多条SQL语句。
UPDATE触发器在UPDATE语句执行之前或之后执行:
OLD
虚拟表访问;对于新值,可以引用NEW
虚拟表访问;NEW
中的值可能也被更新(允许更改将要用于UPDATE语句中的值);OLD
中的值全都是只读的,不能更新。代码如下:
CREATE TRIGGER tri_name
BEFORE UPDATE ON tbl_name FOR EACH ROW
SET NEW.name = Upper(NEW.name);
分析:此代码表示在执行更新前,把将要插入的数据中的name值全部转换为大写,以此来净化插入数据。
DROP TRIGGER [if exists] tri_name;
注意:触发器不能更新或覆盖。为了修改一个触发器,必须先删除它,然后再重新创建。
在JDBC中怎样将多个SQL语句组合成一个事务呢?在JDBC中,打开一个连接对象Connection时,缺省是auto-commit模式,每个SQL语句都被当作一个事务,即每次执行一个语句,都会自动的得到事务确认。为了能将多个SQL语句组合成一个事务,要将auto-commit模式屏蔽掉。在auto-commit模式屏蔽掉之后,如果不调用commit()方法,SQL语句不会得到事务确认。在最近一次commit()方法调用之后的所有SQL会在方法commit()调用时得到确认。
原子性( Atomicity):一组事务,要么全部执行,要么不执行。
一致性 (Consistency):事务执行后,数据库状态与其他业务规则保持一致。如转账业务,无论事务执行成功否,参与转账的两个账号余额之和应该是不变的。
隔离性(Isolation):事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。
持久性(Durability):软、硬件崩溃后,InnoDB
数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit
选项决定什么时候吧事务保存到日志里。
在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。开启事务之后MySQL会关闭自动提交功能。
手动关闭自动提交,代码为:
set autocommit = 0;
开启事务:
start transaction;
-- OR
begin;
结束事务:
commit;
-- OR
rollback;
在执行SQL语句之前,先执行start transaction
,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit
表示提交,即事务中的多条SQL语句所作出的影响会持久到数据库中,或者rollback
,表示回滚到事务的起点,之前做的所有操作都被撤销了。
在JDBC中处理事务,都是通过Connection完成的。同一事务中所有的操作,都在使用同一个Connection对象。
Connection的三个方法与事务有关:
setAutoCommit(boolean)
:设置是否为自动提交事务,如果true(默认值为true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务,如果设置为false,那么相当于开启了事务了。
commit()
:提交结束事务。
rollback()
:回滚结束事务。
JDBC处理事务的代码格式:
try {
con.setAutoCommit(false);//开启事务
......
con.commit();//try的最后提交事务
} catch(Exception e) {
con.rollback();//回滚事务
}
ResultSet是一个游标,每次只能指向某一行,通过游标可以取当前行的列值。游标可以移动指向不同行。
Statement cmd =
conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
ResultSet rs = cmd.executeQuery(sql);
rs.first();//移到第一行
rs.last();//移到最后行
rs.next();//移到下一行
rs.previous();//移到上一行
rs.absolute(4); //移到第4行
rs.relative(2); //在当前行的位置向下2行,如果是负数则向上移动指定行数
Statement cmd =
con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet rs = cmd.executeQuery(sql);
rs.deleteRow(); // 删除当前行
rs.first(); // 移到第一行
rs.updateString(2,"zhang san"); // 更新第2列
rs.updateRow(); // 刷新到数据库
MySQL中定义数据字段的类型对你数据库的优化是非常重要的。
MySQL支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型。
MySQL支持所有标准SQL数值数据类型。
这些类型包括严格数值数据类型(INTEGER
、SMALLINT
、DECIMAL
和NUMERIC
),以及近似数值数据类型(FLOAT
、REAL
和DOUBLE PRECISION)。
关键字INT
是INTEGER
的同义词,关键字DEC
是DECIMAL
的同义词。
BIT数据类型保存位字段值,并且支持MyISAM
、MEMORY
、InnoDB
和BDB
表。
作为SQL标准的扩展,MySQL也支持整数类型TINYINT
、MEDIUMINT
和BIGINT
。下面的表显示了需要的每个整数类型的存储和范围。
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT |
1 byte | (-128,127) | (0,255) | 小整数值 |
SMALLINT |
2 bytes | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT |
3 bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT 或INTEGER |
4 bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT |
8 bytes | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
FLOAT |
4 bytes | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE |
8 bytes | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
DECIMAL |
对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值 |
表示时间值的日期和时间类型为DATETIME
、DATE
、TIMESTAMP
、TIME
和YEAR
。
每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
TIMESTAMP
类型有专有的自动更新特性,将在后面描述。
类型 | 大小 ( bytes) | 范围 | 格式 | 用途 |
---|---|---|---|---|
DATE |
3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
TIME |
3 | ‘-838 : 59 : 59’/‘838 : 59 : 59’ | HH:MM:SS | 时间值或持续时间 |
YEAR |
1 | 1901/2155 | YYYY | 年份值 |
DATETIME |
8 | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
TIMESTAMP |
4 | 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 |
字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。
类型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255 bytes | 定长字符串 |
VARCHAR | 0-65535 bytes | 变长字符串 |
TINYBLOB | 0-255 bytes | 不超过 255 个字符的二进制字符串 |
TINYTEXT | 0-255 bytes | 短文本字符串 |
BLOB | 0-65 535 bytes | 二进制形式的长文本数据 |
TEXT | 0-65 535 bytes | 长文本数据 |
MEDIUMBLOB | 0-16 777 215 bytes | 二进制形式的中等长度文本数据 |
MEDIUMTEXT | 0-16 777 215 bytes | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295 bytes | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295 bytes | 极大文本数据 |
注意:
char(n) 和 varchar(n) 中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符。
CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。
BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。
BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。
有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。
关于 char、varchar 与 text 平时没有太在意,一般来说,可能现在大家都是用 varchar。但是当要存储的内容比较大时,究竟是选择 varchar 还是 text 呢?
这三种类型比较:
总结起来,有几点:
MySQL在建表时,需要有字段名称、字段类型和约束条件,其中字段名称和字段类型是必填的,约束条件是选填的,约束条件主要有PRIMARY KEY、UNIQUE、NOT NULL、DEFAULT等, 一个完整的建表语句如下:
CREATE TABLE students
( sno varchar(4) PRIMARY KEY,
name VARCHAR(10) NOT NULL,
score INT DEFAULT 0
);
NOT NULL是非空的约束,即不能向表里插入空值。还是用students这个表,现在向表里插入数据: INTSERT INTO students VALUE("0002", NULL, 85);
会报错,因为在建表时,姓名字段的约束条件是NOT NULL。
值得注意的是""
空字符串不等同于NULL,我们向表里的姓名字段插入空字符串,INSERT INTO employees VALUE("0003","",18);
是不会报错的,在MySQL里,""
空字符串不是NULL,如果想要输入空值必须是NULL,另外空字符串是可以计算的,比如 SELECT length("");
、SELECT ""+1;
都是有结果输出的。
DEFAULT是在不给字段输入值时,默认的值。我们在创建students表时,分数字段默认为0,向表插入数据:INSERT INTO students(sno,name) VALUE("0004","张三");
,没有向分数字段插入数据,那么就会自动填充0作为默认分数。
当给分数字段插入数据,比如空值NULL,是不会触发default的,向表插入数据:INSERT INTO employees VALUE("0005", "李四", NULL);
,那么李四的分数值就为NULL而不是0,DEFAULT只有在不给字段数据时才会使用。
建表语句如下,我们给姓名字段的约束是非空,如果不给数据,默认为未知:
CREATE TABLE students2
( sno VARCHAR(4) PRIMARY,
name VARCHAR(10) NOT NULL DEFAULT "未知",
score INT
);
根据上文对NOT NULL和DEFAULT的介绍,当向表插入数据时,如果给姓名字段具体值时不会报错;如果给了姓名字段空值NULL时,会触发NOT NULL约束,但不会触发DEFAULT约束,因为DEFAULT只有在不给字段数据时才会使用,所以此条语句报错(因使用了空值);如果不给姓名字段数据,INSERT INTO students2(sno,score) VALUE("0002",90);
,则会触发DEFAULT,给姓名默认值"未知"。
所以NOT NULL和DEFAULT是两个独立的约束,可以用在一个字段上,但不会交互使用,是两个独立的约束条件。另外约束条件不仅是在插入数据时有用,当我们在对表数据进行修改时,也会受到约束条件的限制。
一个或多个数据库操作组成“事务”,也就是说,事务实际上是一组按顺序执行的操作单位。事务具有如下性质(ACID):
事务的开始用 START TRANSACTION,提交用 COMMIT,遇到故障要回滚使用 ROLLBACK(当COMMIT或ROLLBACK语句执行后,事务会自动关闭)。
如下:
SELECT * FROM tbl_name;
START TRANSACTION; -- 开始事务
DELETE FROM ordertotals;
...
COMMIT | ROLLBACK; -- 提交或事务回退
对于ROLLBACK回滚来讲:
默认的MySQL行为是自动提交所有更改,也就是说,任何时候执行MySQL语句,实际上都是立即生效。可以设置不自动提交更改,代码如下:
SET autocommit = 0;
然后要使用COMMIT手动提交。
保留点(save point):
最后,简单提一下,复杂的事务处理可能需要部分提交或回滚,所以在事务处理中的合适位置是可以设置保留点的 ,如下:
SAVEPOINT pointFlagName;
回滚时给出保留点即可:
ROLLBACK TO pointFlagName;
保留点在事务处理完成会自动释放,也可以使用 RELEASE SAVEPOINT 明确地释放保留点。
(1)查看用户
MySQL用户账号和信息存储在名为mysql
的数据库中,mysql
数据库中有一张user
表,它包含所有用户账号。
SELECT user,host FROM mysql.user;
(2)创建用户
CREATE USER user_name IDENTIFIED BY 'pwd';
用户定义为user@host
,即用户名@主机名
,默认主机名为%
。
(3)更改用户名
RENAME USER old_user_name TO new_user_name;
(4)更改密码
SET PASSWORD = PASSWORD('new_pwd'); -- 设置当前用户密码
SET PASSWORD FOR another_user = PASSWORD('new_pwd'); -- 设置其他用户密码(要有权限)
(5)删除用户
DROP USER user_name;
(1)查看权限
SHOW GRANTS FOR user_name;
(2)授予用户权限
GRANT 权限1,权限2 ON 数据库|表|列 TO 用户;
(3)收回用户权限
REVOKE 权限1,权限2 ON 数据库|表|列 FROM 用户;
GRANT和REVOKE可在几个层次上控制访问权限:
GRANT ALL
和REVOKE ALL
;ON db_name.*
;ON db_name.tbl_name
;更多内容,请微信搜索关注公众号【三朝猿老】,第一时间获取更多内容。