知识在乎不断的积累和总结,好记性不如烂笔头.读各种书,以博客以记之,为了自己日后学习查阅,也可以和远方来的朋友分享交流。

简介

  • MySQL 是一个关系数据库系统,支持 SQL 查询语言。
  • MySQL 可以是免费的,你不需要为它付费。
  • MySQL 系统的速度非常快,同样它的性能也是十分优良的。
  • MySQL 是一个管理简捷的数据库,它没有庞大而臃肿的可视化管理工具。

mysql基础命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
USE tablename;
SHOW databases;
SHOW tables;
SHOW columns from tablename;--返回数据表的各个列及属性
DESCRIBE tablename;--等价于上一句
SHOW STATUS;--用于显示广泛的服务器状态信息;
SHOW CREATE DATABASE,SHOW CREATE TABLE--分别用来显示创建特定数据库或表的MySQL语句;
SHOW GRANTS;--用来显示授予用户(所有用户或特定用户)的安全权限;
SHOW ERRORS,SHOW WARNINGS;--用来显示服务器错误或警告消息
--进一步了解SHOW 请在mysql命令行实用程序中,执行命令 HELP SHOW;显示允许的SHOW语句。
-- 检索
SELECT colum_name FROM tablename;
--检索多个列
SELECT colum1,colum2,colum3 FROM tablename;
--检索多个列
SELECT * FROM tablename;
SELECT DISTINCT vend_id FROM tablename;--返回不同(唯一)的vend_id行
--检索指定行
SELECT colum FROM tablename LIMIT 5;--LIMIT 5指示MySQL返回 不多于5行
--为得出下一个5行,可指定要检索的开始行和行数
SELECT colum FROM tablename LIMIT 5,5;
--使用完全限定的表名
SELECT tablename.column FROM databse.tablename;--在有些场景的时候,是需要这样的,多表查询的时候;

排序数据检索

1
2
3
4
5
6
7
SELECT column FROM tablename ORDER BY column;--按单列排序
SELECT column1,column2,column3 FROM tablename ORDER BY column2,column3;
--指定排序方向
SELECT column FROM tablename ORDER BY column DESC;--降序排序
SELECT column1,column2,column3 FROM tablename ORDER BY column2 DESC,column3;--默认是升序ASC
-- 使用ORDER BY 和LIMIT组合可以选出最大和最小
SELECT column FROM tablename ORDER BY column DESC LIMIT 1;

过滤数据

1
2
3
4
5
6
SELECT column1,column2,column3 FROM tablename WHERE column1=value;
-- WHERE子句的位置 在同时使用ORDERBY和WHERE子句时,应 该让ORDER BY位于WHERE之后,否则将会产生错误
-- = 等于<> 不等于 != 不等于 < 小于 <= 小于等于 > 大于 >= 大于等于 BETWEEN 在指定的两个值之间
SELECT column1,column2,column3 FROM tablename WHERE column1 BETWEEN value1 AND value2;
-- 空值检查
SELECT column1,column2,column3 FROM tablename WHERE column1 IS NULL;

数据过滤

1
2
3
4
5
6
7
8
9
10
-- 为了进行更强的过滤控制,MySQL允许给出多个WHERE子句。这些子 句可以两种方式使用:以AND子句的方式或OR子句的方式使用。
-- AND操作符
SELECT column1,column2,column3 FROM tablename WHERE column1=value1 AND column3 < value2;
-- OR操作符
SELECT column1,column2,column3 FROM tablename WHERE column1=value1 OR column3 < value2;
SELECT column1,column2,column3 FROM tablename WHERE (column1 = value1 OR column1 = value2) AND column3 < value2;--不加括号的话,存在优先级选择问题,可能不会产生预期的结果
-- IN 操作符
SELECT column1,column2,column3 FROM tablename WHERE column1 IN (value1,value2) ORDER BY column2;-- 和or功能相似,但是有点就是执行更快,逻辑更清晰,可以包含其他SELECT语句,使得能够更动态地建立WHERE子句
-- NOT操作符
SELECT column1,column2,column3 FROM tablename WHERE column1 NOT IN (value1,value2) ORDER BY column2;

用通配符进行过滤

1
2
3
4
5
6
7
8
9
10
--LIKE操作符
-- 通配符(wildcard) 用来匹配值的一部分的特殊字符
--搜索模式(search pattern)由字面值、通配符或两者组合构成的搜索条件。
-- 谓词 操作符何时不是操作符?答案是在它作为谓词(predi- cate)时。从技术上说,LIKE是谓词而不是操作符。虽然最终 的结果是相同的,但应该对此术语有所了解,以免在SQL文档 中遇到此术语时不知道。
-- 百分号(%)通配符
SELECT column1,column2,column3 FROM tablename WHERE column1 LIKE "value%";--以value为开头的结果
SELECT column1,column2,column3 FROM tablename WHERE column1 LIKE "%value%";-- 所有包含value的
-- 注意NULL 虽然似乎%通配符可以匹配任何东西,但有一个例 外,即NULL。即使是WHERE prod_name LIKE '%'也不能匹配 用值NULL作为产品名的行。
-- 下划线(_)通配符
-- 另一个有用的通配符是下划线(_)。下划线的用途与%一样,但下划线只匹配单个字符而不是多个字符。

正如所见,MySQL的通配符很有用。但这种功能是有代价的:通配 符搜索的处理一般要比前面讨论的其他搜索所花时间更长。这里给出一 些使用通配符要记住的技巧。

  • 不要过度使用通配符。如果其他操作符能达到相同的目的,应该 使用其他操作符
  • 在确实需要使用通配符时,除非绝对有必要,否则不要把它们用 在搜索模式的开始处。把通配符置于搜索模式的开始处,搜索起 来是最慢的
  • 仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据。总之,通配符是一种极重要和有用的搜索工具,以后我们经常会用 到它。

用正则表达式 进行搜索

1
2
3
-- 基本字符匹配
SELECT column1,column2,column3 FROM tablename WHERE column1 REGEXP '1000' ORDER BY column1;
SELECT column1,column2,column3 FROM tablename WHERE column1 REGEXP '.1000' ORDER BY column1;--这里使用了正则表达式.000。.是正则表达式语言中一个特殊的字符。它表示匹配任意一个字符,因此,1000和2000都匹配 且返回。

LIKE与REGEXP 在LIKE和REGEXP之间有一个重要的差别。请 看以下两条语句:

1
2
SELECT column1,column2,column3 FROM tablename WHERE column1 LIKE '.1000' ORDER BY column1;
SELECT column1,column2,column3 FROM tablename WHERE column1 REGEXP '1000' ORDER BY column1;

如果执行上述两条语句,会发现第一条语句不返回数据,而第 二条语句返回一行。为什么?
正如第8章所述,LIKE匹配整个列。如果被匹配的文本在列值 中出现,LIKE将不会找到它,相应的行也不被返回(除非使用 通配符)。而REGEXP在列值内进行匹配,如果被匹配的文本在 列值中出现,REGEXP将会找到它,相应的行将被返回。这是一 个非常重要的差别。
那么,REGEXP能不能用来匹配整个列值(从而起与LIKE相同的作用)?答案是肯定的,使用^和$定位符(anchor)即可.
匹配不区分大小写 MySQL中的正则表达式匹配(自版本 3.23.4后)不区分大小写(即,大写和小写都匹配)。为区分大 小写,可使用BINARY关键字,如WHERE prod_name REGEXP BINARY ‘JetPack .000’。

1
2
3
4
5
6
7
8
9
--进行OR匹配:为搜索两个串之一(或者为这个串,或者为另一个串),使用|,如下所示
SELECT column1,column2,column3 FROM tablename WHERE column1 REGEXP '1000|2000' ORDER BY column1;
-- 匹配几个字符之一两个以上的OR条件 可以给出两个以上的OR条件。例如, '1000 | 2000 | 3000'将匹配1000或2000或3000。
--匹配几个字符之一
SELECT column1,column2,column3 FROM tablename WHERE column1 REGEXP '[123] tom' ORDER BY column1;--1 ton和2 ton都匹配且返回
-- 字符集合也可以被否定,即,它们将匹配除指定字符外的任何东西。 为否定一个字符集,在集合的开始处放置一个^即可。因此,尽管[123] 匹配字符1、2或3,但[^123]却匹配除这些字符外的任何东西。
-- 匹配范围
-- 集合可用来定义要匹配的一个或多个字符。例如,下面的集合将匹 配数字0到9:[0123456789],为简化这种类型的集合,可使用-来定义一个范围。下面的式子功能 上等同于上述数字列表:[0-9],[a-z]匹配任意字母字符道理类似
-- 匹配特殊字符,要用\\转移,\\.,代表搜索含有.字符的

匹配字符类:存在找出你自己经常使用的数字、所有字母字符或所有数字字母字 符等的匹配。为更方便工作,可以使用预定义的字符集,称为字符类(character class)。

  • [:alnum:]:任意字母和数字(同[a-zA-Z0-9])
  • [:alpha:]: 任意字符(同[a-zA-Z])
  • [:blank:]:空格和制表(同[\t])
  • [:cntrl:]:ASCII控制字符(ASCII 0到31和127)
  • [:digit:]:任意数字(同[0-9])
  • [:graph:]:与[:print:]相同,但不包括空格
  • [:lower:]:任意小写字母(同[a-z])
  • [:print:]:任意可打印字符
  • [:punct:]:既不在[:alnum:]又不在[:cntrl:]中的任意字符
  • [:space:]:包括空格在内的任意空白字符(同[\f\n\r\t\v])
  • [:upper:]:任意大写字母(同[A-Z])
  • [:xdigit:]:任意十六进制数字(同[a-fA-F0-9])
    匹配多个实例:
元字符 说明
* 0个或多个匹配
+ 1个或多个匹配(等于{1,})
0个或1个匹配(等于{0,1}) {n} 指定数目的匹配
{n,} 不少于指定数目的匹配
{n,m} 匹配数目的范围(m不超过255)

举例:正则表达式\([0-9] sticks?\):\(匹配),[0-9]匹配任意数字(这个例子中为1和5),sticks?匹配stick 和sticks(s后的?使s可选,因为?匹配它前面的任何字符的0次或1次出 现),\)匹配)。没有?,匹配stick和sticks会非常困难。
[[:digit:]]{4}:匹配连在一起的任意4位数字
定位符
| 元字符 | 说明 |
| :————-: |:————-:|
|^|文本的开始|
|$|文本的结尾|
|[[:<:]]|词的开始|
|[[:>:]]|词的结尾|
^[0-9\.]只在.或任意数字为串中第
一个字符时才匹配它们

创建计算字段

存储在数据库表中的数据一般不是应用程序所需要的格式。下面举
几个例子。

  • 如果想在一个字段中既显示公司名,又显示公司的地址,但这两 个信息一般包含在不同的表列中。
  • 城市、州和邮政编码存储在不同的列中(应该这样),但邮件标签 打印程序却需要把它们作为一个恰当格式的字段检索出来。
  • 列数据是大小写混合的,但报表程序需要把所有数据按大写表示 出来。
  • 物品订单表存储物品的价格和数量,但不需要存储每个物品的总 价格(用价格乘以数量即可)。为打印发票,需要物品的总价格。
  • 需要根据表数据进行总数、平均数计算或其他计算。
    在上述每个例子中,存储在表中的数据都不是应用程序所需要的。 我们需要直接从数据库中检索出转换、计算或格式化过的数据;而不是 检索出数据,然后再在客户机应用程序或报告程序中重新格式化。
    这就是计算字段发挥作用的所在了。与前面各章介绍过的列不同, 计算字段并不实际存在于数据库表中。计算字段是运行时在SELECT语句 内创建的。
    拼接字段
    为了说明如何使用计算字段,举一个创建由两列组成的标题的简单例子。vendors表包含供应商名和位置信息。假如要生成一个供应商报表, 需要在供应商的名字中按照name(location)这样的格式列出供应商的位 置。此报表需要单个值,而表中数据存储在两个列vend_name和vend_country中在MySQL的SELECT语句中,可使用Concat()函数来拼接两个列。
    1
    2
    3
    4
    5
    6
    7
    8
    -- MySQL的不同之处 多数DBMS使用+或||来实现拼接, MySQL则使用Concat()函数来实现。当把SQL语句转换成 MySQL语句时一定要把这个区别铭记在心。
    SELECT Concat(vend_name,'(',vend_country,')') FROM vendors ORDER BY vend_name;
    -- 曾提到通过删除数据右侧多余的空格来整理数据,这可以 使用MySQL的RTrim()函数来完成
    SELECT Concat(RTrim(vend_name),'(',RTrim(vend_country),')') FROM vendors ORDER BY vend_name;
    -- 使用别名
    SELECT Concat(RTrim(vend_name),'(',RTrim(vend_country),')') AS vend_title FROM vendors ORDER BY vend_name;
    -- 执行算数运算
    SELECT product_id,quantity,item_price,quantity*item_price AS price FROM ordertiems WHERE order_num = 20005;

使用数据处理函数

函数:SQL支持利用函数来处理数据。函数一般是在数据上执行的,它给数据的转换和处理提供了方便。去掉串尾空格的RTrim()就是一个函数例子。大多数SQL实现支持以下类型的函数。

  • 用于处理文本串(如删除或填充值,转换值为大写或小写)的文本函数。
  • 用于在数值数据上进行算术操作(如返回绝对值,进行代数运算)的数值函数。
  • 用于处理日期和时间值并从这些值中提取特定成分(例如,返回两个日期之差,检查日期有效性等)的日期和时间函数。
  • 返回DBMS正使用的特殊信息(如返回用户登录信息,检查版本细节)的系统函数。
文本处理函数
1
SELECT name,Upper(name) AS name_upcase FROM tablename ,ORDER BY name;
函数 说明
Left() 返回串左边的字符
Length() 返回串的长度
Locate() 找出串的一个子串
Lower() 将串转换为小写
LTrim() 去掉串左边的空格
Right() 返回串右边的字符
RTrim() 去掉串右边的空格
Soundex() 返回串的SOUNDEX值
SubString() 返回子串的字符
Upper() 将串转换为大写
日期和时间处理函数
函数 说明
AddDate() 增加一个日期(天、周等)
AddTime() 增加一个时间(时、分等)
CurDate() 返回当前日期
CurTime() 返回当前时间
Date() 返回日期时间的日期部分
DateDiff() 计算两个日期之差
Date_Add() 高度灵活的日期运算函数
Date_Format() 返回一个格式化的日期或时间串
Day() 返回一个日期的天数部分
DayOfWeek() 对于一个日期,返回对应的星期几
Hour() 返回一个时间的小时部分
Minute() 返回一个时间的分钟部分
Month() 返回一个日期的月份部分
Now() 返回当前日期和时间
Second() 返回一个时间的秒部分
Time() 返回一个日期时间的时间部分
Year() 返回一个日期的年份部分
1
2
3
4
SELECT id,num FROM tablename WHERE Date(data) = "2017-05-22";
--索出2017年5月下的所有项
SELECT id,num FROM tablename WHERE Date(data) BETWEEN '2017-05-01' AND '2017-05-30';
SELECT id,num FROM tablename WHERE Year(data)=2017 AND Month(date)=9;
数值处理函数
函数 说明
Abs() 返回一个数的绝对值
Cos() 返回一个角度的余弦
Exp() 返回一个数的指数值
Mod() 返回除操作的余数
Pi() 返回圆周率
Rand() 返回一个随机数
Sin() 返回一个角度的正弦
Sqrt() 返回一个数的平方根
Tan() 返回一个角度的正切

汇总数据

聚集数据

我们经常需要汇总数据而不用把它们实际检索出来,为此MySQL提 供了专门的函数。使用这些函数,MySQL查询可用于检索数据,以便分 析和报表生成。这种类型的检索例子有以下几种。

  • 确定表中行数(或者满足某个条件或包含某个特定值的行数)。
  • 获得表中行组的和。
  • 找出表列(或所有行或某些特定的行)的最大值、最小值和平均
    值。
    上述例子都需要对表中数据(而不是实际数据本身)汇总。因此, 返回实际表数据是对时间和处理资源的一种浪费(更不用说带宽了)。重 复一遍,实际想要的是汇总信息。为方便这种类型的检索,MySQL给出了5个聚集函数,见表12-1。 这些函数能进行上述罗列的检索。
函数 说明
AVG() 返回某列的平均值
COUNT() 返回某列的行数
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和
聚集不同值
1
SELECT AVG(DISTINCT price) AS avg_price FROM product WHERE id = 30;
组合聚集函数
1
2
3
4
5
SELECT COUNT(*) AS num_items,
MIN(price) AS price_min,
MAX(price) AS price_max,
AVG(price) AS price_avg
FROM products;

分组数据

GROUP BY子句和HAVING子句,分组允许把数据分为多个逻辑组,以 便能对每个组进行聚集计算。

创建分组
1
SELECT id COUNT(*) AS num_product FROM products GROUP BY id;

具体使用GROUP BY子句前,需要知道一些重要的规定

  • GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套, 为数据分组提供更细致的控制。
  • 如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上 进行汇总。换句话说,在建立分组时,指定的所有列都一起计算
    (所以不能从个别的列取回数据)。
  • GROUP BY子句中列出的每个列都必须是检索列或有效的表达式
    (但不能是聚集函数)。如果在SELECT中使用表达式,则必须在 GROUP BY子句中指定相同的表达式。不能使用别名。
  • 除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子 句中给出。
  • 如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列 中有多行NULL值,它们将分为一组。
  • GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前
过滤分组

除了能用GROUP BY分组数据外,MySQL还允许过滤分组,规定包括 哪些分组,排除哪些分组。例如,可能想要列出至少有两个订单的所有 顾客。为得出这种数据,必须基于完整的分组而不是个别的行进行过滤。在这个例 子中WHERE不能完成任务,因为WHERE过滤指定的是行而不是分组。事实 上,WHERE没有分组的概念。那么,不使用WHERE使用什么呢?MySQL为此目的提供了另外的子 句,那就是HAVING子句。HAVING非常类似于WHERE。事实上,目前为止所 学过的所有类型的WHERE子句都可以用HAVING来替代。唯一的差别是 WHERE过滤行,而HAVING过滤分组。HAVING支持所有WHERE操作符 ,我们学习 了WHERE子句的条件(包括通配符条件和带多个操作符的子 句)。所学过的有关WHERE的所有这些技术和选项都适用于 HAVING。它们的句法是相同的,只是关键字有差别。

1
SELECT id,COUNT(*) AS orders FROM oders GROUP BY id HAVING COUNT(*) >= 2;

HAVING和WHERE的差别 这里有另一种理解方法,WHERE在数据 分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重 要的区别,WHERE排除的行不包括在分组中。这可能会改变计 算值,从而影响HAVING子句中基于这些值过滤掉的分组。
同时使用WHERE和HAVING子句例子:

1
2
SELECT id ,COUNT(*) AS num_prods FROM products WHERE price >= 10
GROUP BY id HAVING COUNT(*)> 2;

分组和排序

虽然GROUP BY和ORDER BY经常完成相同的工作,但它们是非常不同的
| ORDER BY | GROUP BY |
| :————- | :————- |
| 排序产生的输出任意列都可以使用(甚至非选择的列也可以使用) | 分组行。但输出可能不是分组的顺序只可能使用选择列或表达式列,而且必须使用每个选择列表达式 |
|不一定需要|如果与聚集函数一起使用列(或表达式),则必须使用|

1
2
SELECT order_num ,,SUM(quantity* item_price) as ordertotal FROM orderitems GROUP BY order_num
HAVING SUM(quantity* item_price)>= 50 ORDER BY ordertotal;

使用子查询

SQL还允许创建子查询(subquery),即嵌套在其他查询中的查询

1
2
3
4
5
6
7
SELECT cunst_name,cust_contact FROM customers WHERE cust_id IN (
SELECT cust_id FROM orders WHERE order_num IN (
SELECT order_num FROM orderitems WHERE prod_id ='TNT2'
)
);
-- 子查询当嵌套太多的时候,性能就会有问题,联结表会解决这个问题

联结表

SQL最强大的功能之一就是能在数据检索查询的执行中联结(join) 表。联结是利用SQL的SELECT能执行的最重要的操作,很好地理解联结 及其语法是学习SQL的一个极为重要的组成部分。
维护引用完整性 重要的是,要理解联结不是物理实体。换句 话说,它在实际的数据库表中不存在。联结由MySQL根据需 要建立,它存在于查询的执行当中。
在使用关系表时,仅在关系列中插入合法的数据非常重要。回
到这里的例子,如果在products表中插入拥有非法供应商ID (即没有在vendors表中出现)的供应商生产的产品,则这些
产品是不可访问的,因为它们没有关联到某个供应商。
为防止这种情况发生,可指示MySQL只允许在products表的 供应商ID列中出现合法值(即出现在vendors表中的供应商)。 这就是维护引用完整性,它是通过在表的定义中指定主键和外 键来实现的。

创建联结
1
2
3
4
SELECT vend_name,prod_name,prod_price
FROM vendors,products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name,prod_name;
内部联结
1
2
3
SELECT vend_name,prod_name,prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;
联结多个表

SQL对一条SELECT语句中可以联结的表的数目没有限制。创建联结
的基本规则也相同。首先列出所有表,然后定义表之间的关系

1
2
3
4
SELECT prod_name,vend_name,prod_price,quantity
FROM orderitems,products,vendors
WHERE products.vend_id = vendors.vend_id
AND orderitems.prod_id = products.prod_id AND order_num = 2005;

创建高级联结

基础语法

01创建一个表格

1
2
3
4
5
6
7
CREATE TABLE teacher
(
id TINYINT UNSIGNED NOT NULL,
name CHAR(16) NOT NULL,
tele NUMERIC(8),
sex ENUM("F","M") DEFAULT "M"
)

由上面这个例子可以知道,创建列类型的语法是: col_name col_type [col_attributes][general_attributes]

  • col_name 列的名字
  • col_type 列类型,控制存储在列中的数据类型
  • col_attributes 专用属性,只能应用于制定列,例如,我们还不知道的 BINARY。 如果你使用专用属性,必须在列的类型之后,列的通用属性之前。
  • general_attributes 通用属性,可以应用在出少数列的任意列,例如上面提到了 NULL、 NOT NULL、和 DEFAULT。
  • MySQL 的数字列类型

mysql基础配置

创建新用户并给授权指定的数据库权限

给其他工作人员提供某台服务器的 mysql 中某个数据库的访问权限。
之所以要做限制,是防止对其他的数据库非法进行操作。

  • 使用 root 管理员登陆 mysql
    1
    mysql -uroot -p;
  • 创建新用户
    1
    CREATE USER 'user1'@'%' IDENTIFIED BY 'password';

‘%’ - 所有情况都能访问
‘localhost’ - 本机才能访问
’111.222.33.44‘ - 指定 ip 才能访问

  • 注:修改密码

    1
    update mysql.user set password=password('新密码') where user='user1';
  • 给该用户添加权限

    1
    2
    grant all privileges on 想授权的数据库.* to 'user1'@'%';
    #all 可以替换为 select,delete,update,create,drop
  • 删除用户

    1
    Delete FROM mysql.user Where User='user1';
  • 刷新修改

    1
    flush privileges;