这是MySQL系列笔记的第一部分,本系列笔记希望能按照笔者自己学习MySQL技术的经历来记录,避免纯粹按照内容一块一块总结,也就是不同于一般按内容分配章节的书籍的结构,有一个平滑的阅读曲线。内容比较丰富的技术点会按照专题在多个学习笔记中逐渐深入。
这部分的标题叫比CRUD多一丁点儿,比起最基础的w3c的SQL教程之外,只多一点的扩展,满足应付从纯粹阅读入门资料到可以上手完成一个简单的工作的需求。
第二篇的主要内容是基础SQL语句,会根据我工作中的经验,每个语句多介绍一点实际开发中比较常见的用法。
SQL是一种编程语言
SQL是Structure Query Language
的简写。SQL并不只是用来跟数据库,而是一种完备编程语言,在各种编程语言排行榜上也都是名列前茅。SQL语言的历史和C语言一样长,从1970年Codd博士将数据库领域逐渐发扬光大至今近半个世纪,已经可以算是编程语言中的老人了。笔者认为伴随着关系数据库(RDBMS)产生的SQL语言随着软件底层技术的日益成熟,软件应用日益渗透到生活方方面面,软件开发教育也越来越普及(比如前段时间有江苏省已经将Python语言列入高考),未来可能掌握SQL语言的工程师会远远多于掌握C语言的工程师。
同其他语言类似,SQL有标准组织出具的规范,但不同的数据库也有自己的不同的实现。可类比为各种语言有自己的标准,也有不同的编译器(或解释器等)的实现,相信做C++开发的都会被微软的VC编译器和GNU组织的GCC编译器的细微不同而苦恼的经历。这个问题在SQL语言领域应该是更大一些,不同的数据库SQL实现有不小的区别,但基本的看SQL语言可以分为三类:
DML(Data Manipulation Language):数据操纵语句,用户增删查改数据库记录,包括insert, select, update, delete,也就是我们文章标题里面常说CRUD(create read update delete)时候指代的这四个语句。可能入门学习时候一般说的SQL就是指这种类型的。本篇
基础SQL语句
其实也只会介绍此类。DDL(Data Definition Language):数据定义语言,定义数据库、数据表、列、索引等。包括create, drop, alter等。
DCL(Data Control Language):数据控制语句,用于控制不同数据的访问权限,配置密码等。暴扣grant, revoke。
本文下来分别介绍DML中的INSERT
,SELECT
,UPDATE
,DELETE
。
INSERT语句
最简单的形式如下:
insert into table_name(id, cardno, `name`, `desc`) values('1', 100001, "good", "good boy");
复制代码
第一个括号里是列名,第二个括号里是对应顺序的值。
一次插入多条数据:
insert into table_name(id, cardno, `name`, `desc`) values('1', 100001, "good", "good boy"),('2', 100002, "bad", "bad girl");
复制代码
几个常见Tip
顺带说几个常见的小问题,在上面的写法里出现的:
- 表名和列名可以使用“`做转移符,用途是当列名和表名为
desc
,select
这种SQL的关键字和保留字时候必须使用,否则是会报语法错误的。 - 关于保留字和关键字不同,比如
select
是关键字,desc
是保留字具体可看手册。实际上人脑也不会记忆这些关键字,所以在使用时候就全都使用转义就好了。学海无涯,每种技术的缩写、特例等等层出不穷,笔者的习惯是记忆一种比较通用和安全的用法,始终去使用即可。因为很多技术点的多种方法也是一项技术发展的历史原因造成的,并不是说都记着多种办法会有切实的场景。如果表自己创建时候,推荐的做法就还是要过一遍上述链接中的保留字,直接不要使用这些词为好,毕竟这个选名字的时间在建表做设计阶段总的时间比起来并不会占用多少比例。笔者遇到的一些ORM库之类对这些关键字可能并不是处理的十全十美,所以不用是最佳。 - 不止字符型,其实所有插入内容其实都可以用
'
引起来。用'
不用"
还有一个好用的地方是当输入字符串里面有双引号"
时候,可以免于写一级转义。 - 表常常会有自增ID,其实被设置为自增的id也是可以在insert和update时候指定的,只是当不指定值时候才会自增。
INSERT INTO … SELECT 用法:
这是很常用的技巧,当进行数据导入时候会碰到插入的数据需要从另一个表中获取,可以使用insert into ... select
的写法。
例如有供应商和顾客两张表,有一部分列内容是重合的,就如下写法
INSERT INTO Customers (CustomerName, City, Country)
SELECT SupplierName, City, Country FROM Suppliers;
复制代码
但注意,在statement-based的同步中,这种语句是并不安全的。类似的用法还有 INSERT … ON DUPLICATE KEY UPDATE , INSERT IGNORE。可以看手册中的详细介绍。
SELECT语句
最基础的不再赘述,SELECT用法的内容最丰富,后续会专门开一个题。这里说几个常见的Tips。
关于NULL
首先是注意NULL,建表应该避免用NULL值,所有列都可以赋予一个默认值。因为NULL在SELECT、索引、统计函数等很多场合都会有一些让人Surprise的现象,后续可能会单独写一篇关于NULL的博客。
查找NULL时候用IS NULL
, IS NOT NULL
,如果NULL值需要转换,需要用好关于NULL的几个函数IFNULL()
, ISNULL()
, COALESCE()
IFNULL(exp,value)
可以用在语句中代替exp的位置,表示当exp不为NULL时候使用value中的值替代。ISNULL(exp)
做逻辑判断COALESCE(....)
函数是个多值函数,意思是返回这多个参数中按顺序第一个非NULL的值。
ANY和ALL
在各种操作符号如>
,<
,=
后使用ANY和ALL可以表示任意一个和所有的意思。
比如查询比任意Alert表中id大的Account表值:
select id from Account where id > ANY (select id from Alert);
复制代码
比如查询比自己的id还大的(^_^结果当然是没有)
select id from Account where id > ALL (select id from Account);
复制代码
GROUP BY
GROUP BY的基本用法比较常见,但统计函数除了count,sum等还有几个常用的聚合函数(Aggregate Function)。
连接函数 group_concat会将分组内的值组装为一个逗号分隔的数组
select ag.id, ag.name, group_concat(a.id) as resource_ids from AccountGroup ag left join AccountGroup_Account aga on ag.id=aga.account_group_id left join Account a on aga.account_id=a.id group by ag.id;
复制代码
返回会是类似
+----+------------------------------------+--------------+
| id | name | resource_ids |
+----+------------------------------------+--------------+
| 1 | admin | 1,2,3 |
+----+------------------------------------+--------------+
复制代码
count函数可以加distinct表示去重
SELECT COUNT(DISTINCT results) FROM student;
复制代码
更多可以看手册