zoukankan      html  css  js  c++  java
  • MySQL快速入门

    MySQL是一款流行的关系型数据库, 结构化查询语言SQL(Structured Query Language)是关系型数据库通用的操作语言, 但是不同数据库系统的行为还是有着细微的不同, 本文将以MySQL为例进行介绍.

    一个MySql服务实例下可以维护多个database, 其中部分数据库用于维护用户和权限信息. Mysql提供了一些数据库管理语句:

    • SHOW DATABASES; 显示当前实例所拥有的数据库

    • DROP DATABASES db_name; 删除指定数据库

    • CREATE DATABASE [IF NOT EXISTS] db_name; 创建数据库

    • use db_name; 进入数据库

    MySQL将数据存储在数据表中, 数据表由数据库来管理. 此外, 有一些命令可以查看数据表的元信息:

    • SHOW TABLES 显示当前数据库所有数据表

    • DESC <table_name>DESCRIBE <table_name> 显示表结构

    DDL

    数据定义语言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

    数据操作语言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

    查询语句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'; 
    

    字符串可以使用单引号'或双引号"表示.

    上述查询将搜索userpost表中记录所有组合, 满足条件p.uid=u.iduser记录和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 JOINRIGHT JOIN 结果的并集,即左右表只有一个表中有记录即可。

    注意若user表中有m条记录, post表中有n条记录则连接查询将会扫描m*n条记录. 这在表中数据量较大时会非常耗时.

    IN 和 EXISTS 查询

    使用INEXISTS子查询可以完成连接查询的任务.

    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查询作用相同。

    INEXISTS都有对应的否定形式:

    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
    }
    

    允许usernameemail重复, 但不允许任意两条记录在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, 这可能消耗很多时间, 在使用外键时必须要考虑到这一点.

  • 相关阅读:
    笔记-归并排序
    Repeated Substring Pattern
    Assign Cookies
    Number of Boomerangs
    Paint Fence
    Path Sum III
    Valid Word Square
    Sum of Two Integers
    Find All Numbers Disappeared in an Array
    First Unique Character in a String
  • 原文地址:https://www.cnblogs.com/Finley/p/5284865.html
Copyright © 2011-2022 走看看