MySQL是一款流行的关系型数据库, 结构化查询语言SQL(Structured Query Language)是关系型数据库通用的操做语言, 可是不一样数据库系统的行为仍是有着细微的不一样, 本文将以MySQL为例进行介绍.sql
一个MySql服务实例下能够维护多个database, 其中部分数据库用于维护用户和权限信息. Mysql提供了一些数据库管理语句:数据库
SHOW DATABASES;
显示当前实例所拥有的数据库函数
DROP DATABASES db_name;
删除指定数据库工具
CREATE DATABASE [IF NOT EXISTS] db_name;
建立数据库post
use db_name;
进入数据库ui
MySQL将数据存储在数据表中, 数据表由数据库来管理. 此外, 有一些命令能够查看数据表的元信息:code
SHOW TABLES
显示当前数据库全部数据表对象
DESC <table_name>
或 DESCRIBE <table_name>
显示表结构排序
数据定义语言DDL(Data Definition Language)用于操做数据表等数据库对象,对数据表、索引等进行定义。索引
数据表table是行列的逻辑结构, 每行是一条记录, 每列是记录的一个字段. 同一张表的全部记录拥有相同的结构, 建立表时最重要的信息就是表的结构信息.
CREATE TABLE `user` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `username` VARCHAR(20) DEFAULT "", `password` CHAR(20) DEFAULT "", `gender` CHAR(1), `age` INT );
SQL语句不区分大小写, 一般咱们将SQL关键字大写, 自定义标识符小写. 用反点号包括自定义标识符能够避免它们被认为是SQL关键字.
SQL标识符以字母开头, 可使用字母, 数字或三个特殊符号#
, _
, $
.标识符用于表示表, 列和其它对象的名称.
全部DDL语句中的DEFAULT
项都是能够省略的.
MySQL中经常使用的数据类型有:
INT
: 32位有符号整数DOUBLE
双精度浮点数DECIMAL
精确小数CHAR(limit)
, 定长字符串VARCHAR(limit)
变长字符串TEXT
长文本数据DATE
日期DATETIME
日期和时间TIMESTAMP
UNIX时间戳使用drop
语句来删除数据表:
DROP TABLE `user`;
表在建立完成后仍能够修改其结构, 不过要注意对其中数据的影响:
ALTER TABLE `user` DROP `age`;
ALTER TABLE `user` ADD `age` INT DEFAULT 0;
ALTER TABLE `user` CHANGE `gender` `sex` CHAR(1) DEFAULT "M"; ALTER TABLE `user` MODIFY `gender` INT DEFAULT 0;
数据操做语言DML(Data Manipulation Language), 用于操做表中的数据。
插入一条记录:
INSERT INTO `user` (`username`, `password`) VALUES ("abcd", "1234"); INSERT INTO `user` VALUES ("abcd", "1234");
要向全部没有默认值且不容许为空的列插入数据.
更新已存在的记录:
UPTATE `user` SET `username`="abc" WHERE `id`=1;
update
能够更新全部符合WHERE
子句的记录, 当没有WHERE
子句时更新该表全部记录.
当键重复时更新记录, 不然插入记录:
INSERT INTO `user` VALUES ("a", "2") ON DUPLICATE KEY UPDATE `username`="a", "password"=2;
删除记录:
DELETE FROM `user` WHERE `id`=1;
删除全部符合WHERE
子句的记录, 当没有WHERE
子句时删除该表全部记录.
查询语句SELECT是最灵活最复杂也是最重要的SQL语句.
咱们建立用户user
和文章post
两张表作为示例:
CREATE TABLE `user` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `username` VARCHAR(20) DEFAULT "", `password` CHAR(20) DEFAULT "", `gender` CHAR(1), `age` INT ); CREATE TABLE `post` ( id INT PRIMARY KEY AUTO_INCREMENT, uid INT, title TEXT, CONTENT TEXT );
查询user
表中全部记录的全部字段.
SELECT * FROM `user`;
SELECT能够能够查询某个表中符合条件记录的某些字段.如全部男性用户的username:
SELECT `username` FROM `user` WHERE `gender`='M';
咱们可使用LIMIT限制返回结果的数量:
SELECT * FROM `user` LIMIT 10 OFFSET 10;
上述查询跳过前10个(OFFSET 10)结果, 并返回最多10条记录(LIMIT 10)。
在多表查询时可能须要指定列的所在的表:
SELECT `user`.`username` FROM `user` WHERE `user`.`gender`='M';
为了简化表达式能够为列和表指定别名:
SELECT u.`username` AS name FROM `user` u WHERE u.`gender`='M';
表中可能出现用户名相同的状况, 使用DISTINCT
函数去除重复的用户名:
SELECT DISTINCT(`username`) FROM `user`;
MySQL能够进行取平均值, 求和等汇集操做.
SELECT AVG(`age`) FROM `user`;
上述语句查询user
表中全部记录age
字段的平均值. 可使用GROUP BY
子句指定分组汇集方式.
SELECT AVG(`age`) FROM `user` GROUP BY `gender`;
上述语句将gender
字段相同的记录视做一组, 求出age
字段的平均值. 咱们能够附加where子句查询男性用户的平均年龄:
SELECT gender, AVG(`age`) FROM `user` WHERE gender=`M` GROUP BY gender;
WHERE
子句中没法使用汇集函数, 可使用HAVING
子句完成该功能, 好比查询发表文章超过3篇的做者:
SELECT uid FROM `post` HAVING count(id) > 3 GROUP BY uid;
经常使用的汇集函数有:
SUM
求和
AVG
求平均值
MIN
求最小值
MAX
求最大值
COUNT
求记录数
此外还有一些工具函数也顺便介绍:
LENGETH(txt)
, LEN(txt)
: 求文本长度
REPLACE(txt, from, to)
替换文本
UCASE(txt)
, LCASE(txt)
: 转为大写 / 小写
mid(txt, start, len)
: 提取子串
ORDER BY 语句能够根据结果中某一列进行排序:
SELECT * FROM user ORDER BY age DESC LIMIT 10;
把user表中的记录根据age字段进行降序排列, 并返回前10条记录。
SELECT * FROM user ORDER BY age ASC LIMIT 10;
把user表中的记录根据age字段进行升序排列, 并返回前10条记录。
ORDER BY 语句能够进行多列排序:
SELECT * FROM user ORDER BY age DESC, username ASC;
把user表中的记录根据age字段进行升序排列,age相同的根据username字典序升序排列。
ORDER BY 语句能够根据汇集函数进行排序:
SELECT post_id, count(*) as comment_count FROM comment GROUP BY post_id ORDER BY count(*) DESC;
根据文章的评论数进行降序排列。
如今查询全部女性用户发表的文章:
SELECT p.`id` AS post_id, `title`, `content`, u.`username` AS author FROM `user` u, `post` p WHERE p.`uid`=u.`id` AND u.`gender`='F';
字符串可使用单引号
'
或双引号"
表示.
上述查询将搜索user
和post
表中记录全部组合, 知足条件p.uid=u.id
的user
记录和post
记录将组合为同一条记录. 而后查询组合记录中符合条件u.
gender='F'
的记录.
使用等价的join
操做来代替上述查询:
SELECT p.`id` AS post_id, title, content, u.`username` AS author FROM `post` p JOIN `user` u ON p.`uid`=u.`id` WHERE u.`gender`='F';
join
操做有3种:
INNER JOIN
, JOIN
: 查询出的记录必须知足ON
条件,若左表或右表中没有对应的记录,查询结果中均不会包含相应记录。
LEFT JOIN
: 查询左表post
中全部记录, 即便右表中没有对应的记录. 当没有右表记录时, 查询结果中右表的字段为空值.
REIGHT JOIN
查询右表user
中全部记录, 即便左表中没有对应记录. 当没有左表记录时, 查询结果中左表的字段为空值.
OUTER JOIN
: LEFT JOIN
和 RIGHT JOIN
结果的并集,即左右表只有一个表中有记录便可。
注意若user
表中有m条记录, post
表中有n条记录则链接查询将会扫描m*n
条记录. 这在表中数据量较大时会很是耗时.
使用IN
和EXISTS
子查询能够完成链接查询的任务.
SELECT * FROM `post` WHERE `uid` IN ( SELECT `user`.`id` FROM `user` WHERE `gender`='F' );
IN
运算符将匹配uid
和子查询的结果, 若记录的uid
在结果集中则IN
条件为真.
IN
运算符后能够直接书写列表:
SELECT * FROM user WHERE username in ('a', 'b');
查询username为'a'或'b'的用户。
EXISTS
运算符能够起到相似的做用:
SELECT * FROM `post` WHERE EXISTS ( SELECT `user`.`id` FROM `user` WHERE `gender`='F' AND `user`.`id`=`post`.`uid` );
在EXISTS子查询中能够访问外表,如上例exists子查询中访问了post
表。
上述SQL语句查询使EXISTS子查询SELECT user.id FROM user WHERE gender='F' AND user.id=post.uid
结果不为空集的post
记录。即查询女性做者发表的全部文章,与本节开头的IN查询做用相同。
IN
和EXISTS
都有对应的否认形式:
SELECT * FROM `post` WHERE `uid` NOT IN ( SELECT `user`.`id` FROM `user` WHERE `gender`='F' );
SELECT * FROM `post` WHERE NOT EXISTS ( SELECT `user`.`id` FROM `user` WHERE `gender`='F' AND `user`.`id`=`post`.`uid` );
SELECT * FROM
语句能够把另一个查询结果做为数据源。
添加两张表:
CREATE TABLE `likes` ( `uid` INT, `post_id` INT, PRIMARY KEY (`uid`, `post_id`) ); CREATE TABLE `comment` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `uid` INT, `post_id` INT, `content` TEXT, );
咱们要搜索全部文章的点赞like
数和评论comment
数:
SELECT lc.post_id, lc.like_count, cc.comment_count FROM ( SELECT `post_id`, count(*) AS like_count FROM `likes` GROUP BY `post_id` ) lc OUTER JOIN ( SELECT `post_id`, count(*) AS comment_count FROM `comment` GROUP BY `post_id` ) cc ON lc.post_id = cc.post_id;
上述语句中咱们将查询语句SELECT post_id, count(*) AS like_count FROM likes GROUP BY post_id
的结果做为一个数据表, 并给它一个别名lc
。
相似地,咱们将另外一个查询的结果做为数据表cc
, 而后将两个数据表进行JOIN。
MySQL能够根据查询建立视图view
对象, 能够用访问数据表的方式访问视图. 视图只保存查询操做不保存数据, 视图在被访问时从数据表中取出数据.
CREATE VIEW `post_detail` AS SELECT p.`id` AS post_id, title, content, p.`uid` AS author_id, u.`username` AS author_name FROM `post` p JOIN `user` u ON p.`uid`=u.`id` WHERE u.`gender`='F';
SELECT * FROM `post_detail`;
约束是在表上强制执行的校验规则, 用于保证数据的完整性. 约束分为对单列的约束和对多个列集合的约束.
MySQL中全部数据类型均可以使用null, 一般使用field IS NULL
来判断某个字段是否为空.
非空约束限制某一列不容许出现null值, 在建表时添加非空约束:
CREATE TABLE `user` { `username` VARCHAR(20) NOT NULL }
也能够随时添加或删除非空约束:
ALTER TABLE `user` modify `username` VARCHAR(20) NULL;
ALTER TABLE `user` modify `username` VARCHAR(20) NOT NULL;
惟一约束要求单列或列的集合不容许出现多个相同的非NULL值, 不容许username
列出现重复值:
CREATE TABLE `user` { `username` VARCHAR(20) UNIQUE }
容许username
或email
重复, 但不容许任意两条记录在username
相同时email
也相同.
CREATE TABLE `user` { `username` VARCHAR(20), `email` VARCHAR(20), UNIQUE(`username`, `email`) }
为了便于后续操做, 最好使用命名约束:
CREATE TABLE `user` { username VARCHAR(20), email VARCHAR(20), CONSTRAINT uc_user UNIQUE(username, email) }
使用ALTER
添加惟一约束:
ALTER TABLE `user` ADD UNIQUE(`username`);
ALTER TABLE `user` ADD CONSTRAINT uc_user UNIQUE(`username`, `email`);
撤销惟一约束:
ALTER TABLE `user` DROP CONSTRAINT uc_user;
主键是表上的一列或几列的集合, 主键列必须非空且惟一. 主键必须能够惟一肯定表中的记录, 即不存在主键列相同的两条记录.
每一个表最多包含一个主键约束:
CREATE TABLE `user` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `username` VARCHAR(20) DEFAULT "", );
CREATE TABLE `user` { username VARCHAR(20), email VARCHAR(20), CONSTRAINT user_key PRIMARY KEY(username, email) }
使用ALTER
修改主键约束:
ALTER TABLE `user` ADD PRIMARY KEY(`id`);
ALTER TABLE `user` ADD CONSTRAINT user_key PRIMARY KEY(`username`, `email`);
由于最多有一个主键约束, 因此删除时不用指定约束对象:
ALTER TABLE `user` DROP PRIMARY KEY;
外键约束将数据表B上的某列或列集合与数据表A的主键关联, 外键列的结构必须与被参照主键的结构一致, 但容许外键列的值重复. 数据表B上每条记录的外键列必须与被参照表A的某条记录的主键相同.
CREATE TABLE `user` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `username` VARCHAR(20) DEFAULT "", `password` CHAR(20) DEFAULT "", `gender` CHAR(1), `age` INT ); CREATE TABLE `post` ( id INT PRIMARY KEY AUTO_INCREMENT, uid INT, title TEXT, CONTENT TEXT, FOREIGN KEY(uid) REFERENCES user(`id`) );
创建在post
表上的外键能够保证post
表中每条记录的uid都指向user
表中一条记录. 避免存在找不到做者的文章.
当删除被参照表上的某条记录时, 必须删除全部参照它的记录. 即删除用户前必须前必须删除他发表的全部文章, 以保证外键约束不被破坏.
在拥有外键约束的表post
上添加数据时必须扫描一遍被参照的user
, 这可能消耗不少时间, 在使用外键时必需要考虑到这一点.