本博客摘自《MySQL必知必会》,对基础问题进行总结。
1.检索数据
(1)SELECT columnname FROM tablename;返回结果不一定和插入顺序相同,结果是无序的
(2)去掉重复的值 SELECT DISTINCT columnname FROM tablename
(3)限制结果:limit
SELECT * FROM tablename limit 5;结果不能超过5条
SELECT * FROM tablename limit 5,10;将返回从行5开始的10行。注意行号从0开始记数
(4)完全限定的表名
SELECT tablename.columnname FROM databasename.tablename
当多表联合查询时经常会用到这种方式,下面将具体介绍
(5)使用order by 可以对数据进行排序,
SELECT * FROM tablename ORDER BY columnname;对数据按照columnname“升序”排列
SELECT * FROM tablename ORDER BY columnname DESC;对数据按照columnname“降序”排列
按照多列排序用逗号分割
SELECT * FROM tablename ORDER BY columnname1 DESC,columnname2;
对数据按照columnname1“降序”排列,若columnname1相同则按照columnname2升序排列
(6)过滤条件where
操作符 | 说明 |
= <> != < <= > >= BETWEEN a AND b |
等于 不等于 小于 小于等于 大于 大于等于 在指定的两个值之间 |
空值检查:IS NULL(NULL 无值,和0,空字符串不同)
SELECT * FROM tablename WHERE columnname IS NULL
(7)组合where子句 or ,and,in,not
or 和 and与逻辑或和与对应。但是这里要考虑到计算次序的问题,SQL像很多语言一样先处理AND再处理OR
例如:SELECT * FROM tablename WHERE column1 = 10 or column1 = 11 and colum2 > 0的默认执行顺序是
SELECT * FROM tablename WHERE column1 = 10 or (column1 = 11 and colum2 > 0 )
如果想让两个条件先或,则要用括号包起来SELECT * FROM tablename WHERE(column1 = 10 orcolumn1 = 11)and colum2 > 0
in 规定取值必须在某个范围内 SELECT * FROM tablename WHERE column IN (1,2,3);
NOT是WHERE子句中用来否定后跟条件的关键字。mysql支持使用NOT对IN,BETWEEN,EXISTS子句取反。
(8)LIKE操作符
SELECT * FROM tablename WHERE colunm LIKE “%test_”
其中 % _ 都是通配符,%匹配任意字符任意多次 _匹配任意字符一次
(9)REGEXP
使用正则表达式进行匹配。
MySQL用WHERE子句对正则表达式提供了初步的支持,允许你指定用正则表达式过滤SELECT检索出的数据
MySQL仅支持多数正则表达式实现的一个很小的子集。
基本字符匹配
SELECT prod_name FROM products WHERE prod_name REGEXP ' 1000 ' ORDER BY prod_name; ------ 返回 ------ +------------------------+ | prod_name | +------------------------+ | JetPack 1000 | +------------------------+
. 表示匹配任意一个字符。
SELECT prod_name FROM products WHERE prod_name REGEXP ' .000 ' ORDER BY prod_name; ------------ 返回 ----------- +-------------------------+ | prod_name | +-------------------------+ | JetPack 1000 | | JetPack 2000 | +-------------------------+
MySQL中的正则表达式匹配不区分大小写。
为区分大小写,可使用BINARY关键字。
如:WHERE prod_name REGEXP BINARY 'JetPack .000'
进行OR匹配
为搜索两个串之一(或者这个串,或者为另一个串),使用 | 。
| 作为OR操作符,表示匹配其中之一。可给出两个以上的OR条件。
SELECT prod_name FROM products WHERE prod_name REGEXP ' 1000 | 2000 ' ORDER BY prod_name; ------------ 返回 ------------ +----------------------+ | prod_name | +----------------------+ | JetPack 1000 | | JetPack 2000 | +----------------------+
[ ] 匹配任何单一字符。
[123]定义一组字符,意思是匹配1或2或3.
[ ]是另外一种形式的OR语句,[123] Ton 就是 [1 | 2 | 3] Ton 的缩写。
^ 否定一个字符集合,将匹配除指定字符外的任何东西。[^123]将匹配除这些字符外的任何东西。
SELECT prod_name FROM products WHERE prod_name REGEXP ' [123] Ton ' ORDER BY prod_name; ------------- 返回 ------------ +--------------------+ | prod_name | +--------------------+ | 1 ton anvil | | 2 ton anvil | +--------------------+
匹配范围
[0123456789] 或 [0-9] 将匹配数字0到9
[a-z] 匹配任意字母符号
SELECT prod_name FROM products WHERE prod_name REGEXP ' [1-5] Ton ' ORDER BY prod_name; ---------- 返回 ----------- +-------------------+ | prod_name | +-------------------+ | . 5 ton anvil | | 1 ton anvil | | 2 ton anvil | +-------------------+
匹配特殊字符
\\ 为前导。即转义.正则表达式内具有特殊意义的所有字符都必须以这种方式转义。
\\- 表示查找 -
\\. 表示查找 .
SELECT prod_name FROM vendors WHERE vend_name REGEXP ' \\. ' ORDER BY vend_name; ------------- 返回 ------------- +----------------------+ | vend_name | +----------------------+ | Furball Inc. | +----------------------+
\\ 也用来引用元字符(具有特殊意义的字符)
\\f 换页 \\n 换行 \\r 回车 \\t 制表 \\v 纵向制表
匹配字符类
[:a;num:] 任意字母和数字(同 [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\\t\\r\\v]) [:upper:] 任意大小字母(同 [A - Z]) [:xdigit:] 任意十六进制数字(同 [a - fA - F0 - 9 ])
匹配多个实例
元字符 说明 * 0个或多个匹配 + 1个或多个匹配(等于 { 1 , }) ? 0个或1个匹配(等于 {0, 1 }) {n} 指定数目的匹配 {n, } 不少于指定数目的匹配 {n ,m} 匹配数目的范围(m不超过255)
以下例子:s后的?使s可选,因为?匹配它前面的任何字符的0次或1次出现。
SELECT prod_name FROM products WHERE prod_name REGEXP ' \\([0-9] sticks?\\) ' ORDER BY prod_name; ------------ 返回 ------------ +-----------------------+ | prod_name | +-----------------------+ | TNT ( 1 stick) | | TNT ( 5 sticks) | +-----------------------+
匹配连在一直的4位数字:WHERE prod_name REGEXP '[[:digit:]]{4}'
定位符
^ 文本的开始 $ 文本的末尾 [[: < :]] 词的开始 [[: > :]] 词的结尾
SELECT prod_name FROM products WHERE prod_name REGEXP ' ^[0-9\\.] ' ORDER BY prod_name; ----------- 返回 ---------- +---------------------+ | prod_name | +---------------------+ | . 5 ton anvil | | 1 ton anvil | | 2 ton anvil | +---------------------+
^的双重用途:在集合中(用[ ]定义),用它来否定该集合。否则,用来指串的开始和。
LIKE 匹配整个串,而REGEXP匹配子串。
简单的正则表达式测试 可以在不使用数据库的情况下用SELECT来测试正则表达式。
REGEXP检查总是返回0(没有匹配)或1(匹配),可以用带文字串的REGEXP来测
试表达式,并试验它们。相应的语法如下:
SELECT 'hello' REGEXP '[0-9]'
这个例子返回0(因为文本hello中没有数字)。
(10)拼接字段,别名,执行算术计算
SELECT Concat(column,'('column2,')') FROM tablename
将返回数据格式未 colunm(column2)
AS 关键字用来给列或者表定义别名。SELECT Concat(column,'('column2,')') AS newcolumn FROM tablename
存储在表中的数据一般不是应用程序所需要的格式。我们需要直接从数据库中检索出转换、计算或格式化的数据。而不只是检索出数据,然后再到应用程序或报告程序中区格式化。
这就发挥了计算字段的作用了。与前面的字段不同,计算字段并不实际存在于数据库中。计算字段是运行时在SELECT 语句中创建的。
需要注意的是,只有SELECT语句知道那些列是实际列,哪些列不是,客户机的角度来看,计算字段和其他字段是一样的。
拼接字段
拼接:将值联结到一起构成单个值。
生成供应商 columnOne(columnTwo) 的格式
SELECT Concat(columnOne, '(' , columnTwo, ')') FROM table ORDER BY columnOne;
使用别名
别名使用AS关键字赋予
执行算术运算
另一常见的用途就是对检索出来的数据进行算术运算。
例如:检索出column_id 为2005的columnOne乘以columnTwo的值
SELECT column_id, columnOne, columnTwo, columnOne*columnTwo AS column_price FROM table WHEREcolumn_id = 2005
操作符 + - * /
SELECT 3*2;将返回6
SELECT Now(); 返回当前的日期和时间
2.函数
(1)常用文本函数
SQL实现了一下类型的函数
1 用于处理文本串,如删除、填充、装换大小写
2 用于数据上进行的算术操作,如返回绝对值,进行代数运算
3用于处理日期和时间值并从这些值中提取特定的成分,如返回两个日期差,检查日期有效性
4 返回DBMS正使用的特殊信息 ,如用户登录信息,检查版本细节信息
文本处理函数
Upper() 将文本转换为大写
SELECT vend_name, Upper(vend_name) AS vend_name_upcase FROM vendors ORDER BYvend_name;
常用的文本处理函数
Left() 返回串左边的字符
Length() 返回串的长度
Locate() 找出串的一个子串
Lower() 将串转换为小写
Right() 返回右边的字符
Soundex() 返回串的SOUNDEX值
SubString() 返回串的字符
Upper() 将串转换ewing大写
Soundex()是一个将任何文字串转换为描述语音表示的字母数字模式的算法。他考虑了类似发信字符和音节,使得能对串进行发音的比较而不是字母比较,如:Y.lee搜索可以匹配Y.lie
SELECT cust_name , cust_contact FROM customers WHERE Soundex(cust_contact) =Soundex('Y Lie')
删除多余空格的函数
RTrim() LTrim() Trim() 依次是删除 右边 左边 两边的空格
SELECT Concat(RTrim(vend_name), '( ' ,RTrim(vend_country), ') FROM vendors ORDER BYvend_name;
日期和时间处理函数
日期和时间常用相应的数据类型和特色的格式存储,以便能快速和有效的排序或过滤,并节省物理存储空间。
AddDate() 增加一个日期 天、周等
AddTime() 增加一个时间 时、分等
CurDate() 返回当前日期
CurTime() 返回当前时间
Date() 返回日期时间的日期部分
DateDiff() 计算两个日期之差
Date_Add() 高度灵活的日期或时间串
Date_Format() 返回一个格式的日期或时间串
Day() 返回一个日期的天数部分
DayOfWeek() 对于一个日期,返回对于星期几
Hour() 返回一个时间的小时部分
Minute() 返回一个时间的分钟部分
Moth() 返回一个日期的月份部分
Now() 返回当前的日期和时间
Second() 返回一个时间的秒部分
Time() 返回一个日期时间的时间部分
Year() 返回一个日期的年份部分
MySQl日期格式必须为yyyy-mm-dd,如2010-05-03。虽然其他日期格式也行,但这是首选格式,因为他排除了多义性。
例如,存储的日期列中的日期是2010-11-05 15:23:05 如果想找出2010-11-05这天的数据,使用前面的语句就不行了。这是要使用Date()函数指示mysql提取列的日期的部分
SELECT cust_id, order_num FROM orders WHERE Date(order_date) = '2010-11-05';
检索出2005-5月份的订单怎么办呢?可以使用BETWEEN
SELECT cust_id,order_num FROM orders WHERE Date(order_date) BETWEEN '2005-05-01' AND '2005-05-30';
还有一种不需要记住天数的函数Month(),使年份相等,再让月份相等就行了
SELECT cust_id,order_num FROM orders WHERE Year(order_date) = 2005 ANDMonth(order_date) = 5;
数值处理函数
Abs() 返回一个数的绝对值
Cos() 返回一个角度的余弦
Exp() 返回一个数的指数值
Mod() 返回除操作的余数
Pi() 返回圆周率
Rand() 返回一个随机数
Sin() 返回一个角度的正弦值
Sqrt() 返回一个数的平方根
Tan() 返回一角度的正切
Msyql提供这些函数以便分析和报表生成,这种类型的检索例子有以下几种:
汇聚函数 :运行在行组上,计算和返回单个值的函数
1 确定表中的行数(或者满足某个条件或包括某个特定的值的行数)
2 获得表中行组的和
3 找出表列(或所有行或某特定行的)最大值、最小值和平均值
AVG() 返回某列的平均值
COUNT() 返回某列的行数
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和
求products表中产品的平均价格
SELECT AVG(prod_price) AS avg_price FROM products;
求products表中编号为1003产品的平均价格
SELECT AVG(prod_price) AS avg_price FROM products WHERE vend_id = 1003;
AVG()函数只能用来确定特定数值列的平均值,而且名必须作为函数参数给出。为了获得多个平均值,必须使用多个AVG()函数,AVG()函数忽略列值为NULL的行
COUNT()函数的两种使用方式:
1 COUNT(*) 对表中的数目进行计数,不管表列中包含的是NULL值还是非空值
2 COUNT(column) 对特定的列中具有值的进行计数,忽略NULL值
SELECT COUNT(*) AS num_cust FROM customers;
SELECT COUNT(cust_email) AS num_cust FROM customers;
MAX()函数 ,忽略列值为NULL的行
SELECT MAX() AS max_price FROM products;
MIN() 与MAX()函数一样
SUM() 函数
SELECT SUM(quantity) AS items_ordered FROM orderitems WHERE order_num = 2005
下面是mysql5以后的函数 在mysql4中不能正常运行
DISTINCT 参数,作用是返回不相同的值
下面是返回供应商提供的产品的平均值,它与上面的SELECT 语句相同,但使用了DISTICT参数,因此平均值只考虑各个不同价格合起来的平均值
SELECT AVG(DISTINCT prod_price) AS avg_price FROM products WHERE vend_id=10003;
如果指定了列名,DISTINCT参数只能用于COUNT(),DISTINCT参数不能用于COUNT(*)应为DISTINCT必须使用列名。
3.分组 GROUP BY /HAVING
这两个关键字很重要,在面试题中经常会出现。2015,2016腾讯笔试题中的sql都需要利用group by + having
分组允许把数据分成多个逻辑组,比便能对每个组进行聚集计算。
分组是在SELECT 语句的 GROUP BY 子句中建立的。
返回每个厂商提供了几个产品
SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id;
GROUP BY 一些重要规定
1 GROUP BY 子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据分组提供了更细致的控制
2 如果在GROUP BY 子句中嵌套了分组,数据将在最后规定的分组上进行汇总,换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别列取回数据)
3 GROUP BY 子句列出的每个列都必须是检索列或有效的表达式,(但不能是聚集函数)如果。在SELECT 中使用了表达式,则必须在GROUP BY 子句中指定相同的表达式,不能使用别名。
4 除聚集计算语句外,SELECT 语句中的每个列都必须在GROUP BY 子句中给出
5 如果分组列中具有NULL值,不管一个或多个都将作为一个分组返回
6 GROUP BY 子句必须出现在WHERE 子句之后,GROUP BY 子句之前
过滤分组
如想要得到大于3的不同产品订单
WHERE 是过滤指定的行而不是列。 HAVING 支持所有 WHERE 操作符。
SELECT cust_id, COUNT(*) AS orders FROM orders GROUP BY cust_id HAVING COUNT(*) >3;
WHERE 是在分组前进行过滤, HAVING 是在分组后进行过滤
分组和排序区别
ORDER BY GROUP BY
排序产生的输出 分组行,单输出可能不是分组的顺序
任意列都可以使用(甚至 只可能使用选择列或表达式,而且必须使用每个选择列表达式
是分选择列也可以使用) 如果与聚集哈思楠一起使用列(或表达式)则必须使用
不一定需要
例子:检索总计订单价格大于50的订单号和总计订单
SELECT order_num , SUM(quantity* item_price) AS ordertotal FROM orderitems GROUP BYorder_num HAVING SUM(quantity*item_price) >= 50;
按订单价格进行排序 ,后面加 ORDER BY ordertotal;
SELECT 子句顺序
SELECT 要返回的列或表达式
FROM 从中检索数据的表
WHERE 行级过滤
GROUNP BY 分组说明
HAVING 组级过滤
ORDER BY 输出排序顺序
LIMIT 要检索的行数
4.子查询
Sql还允许使用子查询,即嵌套在其他查询中的查询。
利用子查询进行过滤
SELECT cust_id FROM orders WHERE order_num IN(
SELECT order_num FROM orderitems WHERE prod_id = 'TNT2'
)
可以把一条SELECT语句返回的结果用于另一条SELECT语句的WHERE 子句
格式化sql 包含子查询的sql语句难以阅读,可以使用适当的缩进。
得到了订购物品TNT2的所有客户ID,下一步是检索这些客户的信息,总语句是
SELECT cust_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'
)
)
列必须匹配 在WHERE子句中使用子查询,应该保证SELECT语句具有WHERE 子句中相同数目的列。通常子查询将返回的单个列于单个列匹配,但如果需要也可以多个列。
虽然子查询一般与IN操作符结婚使用,但也可以用于测试等于、不等于等符号
作为计算字段使用子查询
使用子查询的另一个方法是创建计算字段。
假设需要显示sustomers表中每个客户的订单总数。
SELECT cust_name ,cust_state,(
SELECT COUNT(*) FROM orders WHERE orders,coust_id = customers . Cust_id
) AS orders FROM customers ORDER BY cust_name;