上一篇笔记传送: MySQL笔记(一):设计范式、基础概念、数据库定义语言DDL
INSERT INTO 表名 VALUES (, , );
例
mysql> INSERT INTO student values(
-> 26221011,
-> 'Alice',
-> 'female');
如果插入的数据与列一一对应,那么可以省略列名,如果希望向指定列上插入数据,则需要指定列名
INSERT INTO 表名(列名1,列名2) VALUES (值1,值2);
也可以一次性插入多个数据
INSERT INTO 表名(列名1,列名2) VALUES (值1,值2),(值1,值2),(值1,值2);
如果忘记添加WHERE
,那么将修改整张表的数据
UPDATE 表名 SET 列名 = 值, ... WHERE 条件 ;
DELETE FROM 表名 WHERE 条件;
-- 指定查询某一列数据
SELECT 列名[,列名] FROM 表名
-- 会以别名显示此列
SELECT 列名 别名 FROM 表名
-- 查询所有的列数据
SELECT * FROM 表名
-- 只查询不重复的值
SELECT DISTINCT 列名 FROM 表名
SELECT * FROM 表名 WHERE 条件 ;
一般的比较运算符,包括=、>、<、>=、<=、!=等。
是否在集合中:in、not in
通配符:like,not like, %(表示任何字符出现任意次数),_(只匹配单个字符)
使用通配符的技巧
逻辑操作符:and、or、not
BETWEEN AND 和 IS NULL
SELECT * FROM student WHERE sid like %03; // 以03结尾的
SELECT * FROM student WHERE name not in('Alice','Bob');
SELECT * FROM student WHERE name not in('Alice','Bob') and sid like %03;
SELECT * FROM student WHERE name IS NULL;
SELECT * FROM student WHERE sid BETWEEN 26221010 AND 26221014;
ASC
表示正序、 DESC
表示降序,默认升序;关键字只应用到直接位于前面的列名
ORDER BY 应该位于 WHERE 的后面
SELECT * FROM 表名 WHERE 条件 ORDER BY 列名1 ASC| DESC, 列名2 ASC|DESC;
对查询结果进行分组,通常需要结合聚合函数一起使用
SELECT sum(*) FROM 表名 WHERE 条件 GROUP BY 列名 ;
通过添加having,来增加约束条件
SELECT sum(*) FROM 表名 WHERE 条件 GROUP BY 列名 HAVING 约束条件
通过limit
来限制查询的数量,只取前n个结果:
注:检索出来的第一行为行0
LIMIT 开始行, 行数;
LIMIT 行数 OFFSET 开始行; #MySQL 5 开始支持
SELECT * FROM 表名 LIMIT 数量
SELECT * FROM 表名 LIMIT 起始位置,数量
多表查询会通过连接转换成单表查询
直接查询会得到两张表的笛卡尔积,也就是每一项数据都和另一张表的数据结合一次,因此产生庞大的数据
如果两个表中都带有一样的属性,需要添加前缀来表明是哪一张表的数据
SELECT * FROM 表1, 表2 WHERE 条件
自身连接查询,就是将表本身和表进行笛卡尔积计算,得到结果,但是由于表名相同,所以要先起一个别名
SELECT * FROM 表名 别名1, 表名 别名2
自身连接查询和前面是一样的, 只不过连接对象变成了自己和自己
外连接就是专门用于联合查询情景的,比如我们希望把两张表结合起来查看完整的数据,就可以通过使用外连接来进行查询,外连接有三种方式
inner join
进行内连接,只会返回两张表的交集部分
通过使用left join
进行左连接,不仅会返回两个表满足条件的交集部分,也会返回左边表中的全部数据,而在右表中缺失的数据会使用null
来代替(右连接right join
同理)
可以将查询结果作为另一个查询的条件
SELECT * FROM 表名 WHERE 列名 = (SELECT 列名 FROM 表名 WHERE 条件)
mysql> SELECT * FROM student WHERE sid = (SELECT sid FROM teach WHERE tid = (SELECT tid FROM teacher WHERE name = 'Allay'));
基本上与列的意思相同,经常互换使用;但是数据库列一般称为列,而术语字段通常用在计算字段的连接上;
只有数据库能区分SELECT语句中哪些是实际的表列,哪些列是计算字段;从客户机(应用程序)的角度来看,计算字段的数据和其他列的数据是以相同的方式返回的
在MySQL中的select语句,可以使用Concat
来拼接两列
mysql> SELECT Concat(Rtrim(name), '( ',Rtrim(sex),')')
-> FROM student
-> ORDER BY name;
+------------------------------------------+
| Concat(Rtrim(name), '( ',Rtrim(sex),')') |
+------------------------------------------+
| Allay( female) |
| Bob( male) |
| Casey( female) |
| David( male) |
| Elien( female) |
| fairy( female) |
+------------------------------------------+
MySQL除了支持前面使用到的Rtrim()以外,还有Trim()
, Ltrim()
,分别是去掉串左右两边的空格,去掉串右边的空格
是一个字段或者值的替换名,用AS
赋予;有时也称为导出列
任何客户机引用都可以按名引用这个列,就像他是一个实际的表列一样
mysql> SELECT price,
-> number,
-> price * number AS expanded_price
-> FROM purchase;
+-------+--------+----------------+
| price | number | expanded_price |
+-------+--------+----------------+
| 2 | 100 | 200 |
| 3 | 23 | 69 |
| 12 | 76 | 912 |
+-------+--------+----------------+
3 rows in set (0.00 sec)
在实际的表列包含不符合规定的字符(如空格)时重命名;在原来的名字容易混淆时扩充它;
函数的可移植性没有SQL强,所以要确保做注释
大多数SQL支持以下类型的函数
关于SOUNDEX
是一个将任何文本串转换为描述其语音表示的字母数字模式的算法,它考虑了类似的发音字符和音节,使得能对字符串进行发音比较而不是字母比较
SELECT cust_name, cust_contact
FROM Customers
WHERE SOUNDEX(cust_contact) = SOUNDEX('Michael Green');
日期和时间处理函数采用相应的数据类型和特殊的格式存储,以便能快速有效地排序或者过滤,并且节省物理存储空间
它总是被用来读取、统计和处理这些值,在MySQL当中有着重要的意义
数据经常需要用日期进行过滤,首先需要注意的时MySQL的日期格式均为yyyy-mm-dd
,排除了多义性
SELECT cust_id, order_num
FROM orders
WHERE order_date = '2023-05-07';
但是这种会出问题,因为date的类型为datetime
,它同时存储日期与时间值,因此我们就需要用到Date()
函数,仅仅提取日期部分
SELECT cust_id, order_num
FROM orders
WHERE Date(order_date) = '2023-05-07';
如果想要提取一个自然月的订单:
第一种方法就是使用 BETWEEN
WHERE Date(order_date) BETWEEN '2023-04-01' AND '2023-04-30';
第二种方法:分别提取比较
WHERE Year(order_date) = 2023 AND Month(order_date) = 9;
聚集函数用来汇总数据,这些函数是高效设计的,返回结果一般比在自己的客户机应用程序中计算的要快得多
包括:
SELECT count(distinct 列名) FROM 表名 AS 别名 WHERE 条件 ;
SELECT COUNT(DISTINCT name) FROM student; //注意中间没有空格
DISTINCT
关键字应用于所有列,而不仅是他的前置列,除非指定的两个列相同,否则所有行都会被检测出来
如果指定列名,DISTINCT只能用于Count()而不是Count(*),也就是不允许使用Count(DISTINCT);
DISTINCT不能用于计算或表达式,必须使用列名
分组是在SELECT语句中的GROUP BY子句中创建的
mysql> SELECT sid,
-> COUNT(*) AS num
-> FROM teach
-> GROUP BY sid;
+----------+-----+
| sid | num |
+----------+-----+
| 26221011 | 1 |
| 26221012 | 1 |
| 26221014 | 1 |
| 2 | 2 |
+----------+-----+
4 rows in set (0.00 sec)
使用ROLLUP使用 WITH ROLLUP
关键字,可以得到每个分组以及每个分组汇总级别(针对每个分组的值)
mysql> SELECT sid,
-> COUNT(*) AS num
-> FROM teach
-> GROUP BY sid WITH ROLLUP;
+----------+-----+
| sid | num |
+----------+-----+
| 2 | 2 |
| 26221011 | 1 |
| 26221012 | 1 |
| 26221014 | 1 |
| NULL | 5 |
+----------+-----+
5 rows in set (0.00 sec)
WHERE过滤行,HAVING过滤分组
这里有另一种理解方法,WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重要的区别,WHERE排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组
mysql> SELECT sid,
-> COUNT(*) AS num
-> FROM teach
-> GROUP BY sid
-> HAVING COUNT(*) > 1;
+-----+-----+
| sid | num |
+-----+-----+
| 2 | 2 |
+-----+-----+
1 row in set (0.00 sec)
例:返回过去十二月内有两个以上订单的顾客
SELECT vend_id, COUNT(*) AS num_prods
FROM products
WHERE prod_price >= 10
GROUP BY vend_id
HAVING COUNT(*) >= 2;
用子查询测试和调试查询很有技巧性,特别是在这些语句的复杂性不断增加的情况下更是如此。用子查询建立(和测试)查询的最可靠的方法是逐渐进行,这与MySQL处理它们的方法非常相同。
首先,建立和测试最内层的查询然后,用硬编码数据建立和测试外层查询,并且仅在确认它正常后才嵌入子查询。这时,再次测试它。对于要增加的每个查询,重复这些步骤
这样做仅给构造查询增加了一点点时间,但节省了以后(找出查询为什么不正常)的大量时间,并且极大地提高了查询一开始就正常工作的可能性。
子查询最常见的使用是在WHERE子句的IN操作符中,以及用来填充计算列
mysql> SELECT sid
-> FROM student
-> WHERE name IN (SELECT tid
-> FROM teach
-> WHERE sid > 1);
Empty set, 6 warnings (0.00 sec)
在SELECT语句中,子查询总是从内向外处理
在使用子查询语句时,要注意分解为多行并且适当的缩进;能极大的简化子查询的使用
使用子查询的另外一种方式是创建计算字段
SELECT cust_name,
cust_state, (SELECT COUNT(*)
FROM orders
WHERE orders.cust_id = customers.cust_id) AS orders FROM customers
ORDER BY cust_name;
涉及外部查询的子查询
任何时候只要列名可能有多义性就必须使用该语法(表名和列名由点号隔开),如果不完全限定列名,会出现歧义;所以必须限定有歧义性的列名
CREATE USER 用户名 IDENTIDIED BY 'PASSWORD';
CREATE USER 用户名 IDENTIDIED BY RANDOM PASSWORD;
示例
mysql> CREATE USER Robot IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.05 sec)
mysql> CREATE USER REST IDENTIFIED BY RANDOM PASSWORD;
+------+------+----------------------+-------------+
| user | host | generated password | auth_factor |
+------+------+----------------------+-------------+
| REST | % | Ou&]*FQdgw[ZHQb&DTo< | 1 |
+------+------+----------------------+-------------+
1 row in set (0.04 sec)
首先需要添加一个MySQL Server 的环境变量,然后通过cmd进行登录
C:\Users\lenovo>mysql -u Robot -p
访问数据库
show databases;
可以通过使用grant
来为数据库用户进行授权
grant all|权限1,权限2...(列1,...) on 数据库.表 to 用户 [with grant option];
grant all on need.* to Robot;
mysql> grant select, update(name) on need.student to Robot;
其中all代表授予所有权限,当数据库和表为*
,代表为所有的数据库和表都授权。如果在最后添加了with grant option
,那么被授权的用户还能将已获得的授权继续授权给其他用户
我们可以使用revoke
来收回一个权限:
revoke all|权限1,权限2...(列1,...) on 数据库.表 from 用户