如题:2019年10月
除前两问是涉及关系代数的内容外,其他都是SQL的查询的考察,足见这部分的重要性。
其实是完成了下面的复习后,再来填的答案:
26、看到“女”这个条件,应该想到是选择。所以是 σ性别=女(采购)
27、商品名,生产日期是属性,所以是投影。π商品名,生产日期(商品)
28、应该是可以想到between ...and
select 商品编号
from 商品
where 价格 between 10 and 15;
29.分析:查询的是商品编号、采购日期、采购数量,属于采购这个关系
条件:刘聪,采购员姓名,属于采购员这个关系,到这里,基本就可以得出,两个关系是通过“编号”这个外键联系起来的。
题目要求用(嵌套查询),也就是子查询实现。子查询,要实现的就是“外表”的返回‘编号’,主查询,查询“内表”的编号对应的要返回的内容。所以:
select 商品编号,采购日期,采购数量
from 采购
where 编号 in (select 编号 from 采购员 where 姓名=‘刘聪’);
30.分析:编号、商品编号、采购日期,都属于采购这个关系,那么采购可以当作视图的基表
条件是采购数量大于100,这个其实是基表的条件。还有一点就是视图的语法:
create view VSC 商品编号,编号,采购日期
as
select 商品编号,编号,采购日期
from 采购
where 采购数量 > 100;
再比如:2018年4月
四、设计题
某职工管理系统的数据库包含如下关系表:
职工(职工号,姓名,性别,年龄)
工程(工程号,工程名称,预算)
报酬(职工号,工程号,工资)
36、分析:这个关系代数不同于之前的真题,题中有三个属性要查询,年龄,姓名,性别,这三个属性都在职工这个关系中,
年龄不在30到50显然是条件,可以写出 σ年龄<30 U 年龄>50(职工),这里不要写错,是并的关系,注意概念,不要想当然。
到这里还没有完,还有两个属性,姓名,性别是用选择呢?还是投影?
选择是从行的角度选择符合条件的元组,这里重要区别是选择的条件一般是列的值域。
投影是从列角度选择若干列。投影的条件一般是列名。
显然,这里要投影。答案:π姓名,性别( σ年龄<30 U 年龄>50(职工))
37、分析:姓名在职工这个关系,工程名称在工程这个关系,工资在报酬这个关系,这个就比较新鲜了。
首行想到的是用内联结,很明显答案是基于SQL的语法的。给出mysql的答案
select a.姓名,b.工程名称,c.工资
from
报酬 as c join 工程 as b on c.工程号=b.工程号
join 职工 as a on 报酬.职工号=职工.职工号;
38、分析:属性就两个职工号 ,总收入,这两个都在报酬这个关系中,送分题:
select 职工号,sum(工资)as '总收入'
from 报酬
group by 职工号;
39、属性一个是预算,这个带有条件10000以上,这肯定是一个选择,属于工程这个关系
另一个属性是工资,提高(也就是修改)属于报酬这个关系,通过外键 工程号与工程相关联。
update 报酬 #修改一定是update,而不是update table
set 工资=工资*1.01
where 工程号 in
(select 工程号 from 工程 where 预算>=10000);
40、答案估计还是SQLserver的,写出 mysql的
涉及到的属性,职工号,是职工关系的主键,报酬关系的外键
姓名,职工的非主属性。
工程名称,工程的非主属性
工资,报酬这个关系的主键,创建包含这四个属性的视图
属于三个不同的关系,mysql的话要用连接,用会连接呢?先看工资和职工号,可通过报酬这个关系直接查询到,姓名的话,也可通过报酬的职工号==职工的职工号来进行内连接(也就是取交集)或左连接(将中间表也就是包含其他表的主键的表,作为左表,这个中间表很重要尤其是对于三个以上的连接的情况,即使没有给出,也要先得到中间表才能进行连接)。这部的结果如下:
内连接是返回两表的职工号相等的记录
在连接是返回左表中全部记录,存在只有工程号,没有职工号和工资的情况,但不符合,职工号相等的条件,所以被舍去,两者结果是一样。
报酬 | 职工 | |||||
职工号 | 工程号 | 工资 | 职工号 | 姓名 | 性别 | 年龄 |
工程名称完全依赖于工程号的,而工程号又是报酬的外键,也是取交集,所以也是内连接,同理,由于条件的存在,所以也适用于左连接。情况如下:
报酬 | 职工 | 工程 | |||||||
职工号 | 工程号 | 工资 | 职工号 | 姓名 | 性别 | 年龄 | 工程号 | 工程名称 | 预算 |
create view VPS
as
select a.职工号,a.工资,b.姓名,c.工程名称
from 报酬 as a left join 职工 as b
on a.职工号=b.职工号
left join 工程 as c on c.工程号=a.工程号;
其实是用户操作关系型数据库的接口语言。SQL语句用于取回和更新数据库中的数据。
每一种数据库有自己版本的SQL语言,但是为了与ANSI标准相兼容,SQL必须以相似的方式共同地来支持一些主要的关键词(比如 SELECT、UPDATE、DELETE、INSERT、WHERE等等)。
除了SQL标准之外,大部分SQL数据库程序都拥有自己的私有扩展。
总体分类?详见《数据库考点之SQL语句(数据库、表、索引、视图)》,不再重复了,单列查询部分
DQL:Data Query Language是SQL语言的核心功能
用于查询数据库对象中所包含的数据,能够进行单表查询、连接查询、嵌套查询,以及集合查询等各种复杂程度不同的数据库查询,并将数据返回到客户机中显示。其数学理论基础是关系代数中的选择、投影、连接。
select语法:
select
[all | distinct |distinctrow]
select_expr [,select_expr ...]
from table_references
[where where_condition]
[group by {col_name | expr | position}
[asc | desc],...[with rollup]]
[having where_condition]
[order by {col_name | expr | potin}
[asc | desc],...]
[limit {[offset,]row_count | row_count offset offset}]
注:只有 select from是必须的,其他都是可选的。并且其他可选项都要按照语法顺序所使用。
distinct:不同,含义为:指定是否返回结果集中重复的行。与distinct row同义,指向select语句中指定的所有的列,而不仅仅是前置的某个列。
那么有没有什么记忆技巧呢?
首先,如果给我们一张表,我们是从(from)这张表开始查,然后如果需要过滤就(where)过滤,之后如果引用了聚合函数,就需要进行分组(group by),接下来如果我们需要对这前面阶段–分组得到的结果进行二次过滤的时候,就用到(having)进行过滤,只要记住,having只服务于group by就行了,经过这么多步骤得出来的结果后我们选择(select)哪些需要显示的用什么顺(order by )显示出来,如果是mysql 数据库,最后还可以加个限制(limit)取出来的条数。
通过这些关键词,可以知道个大概操作数据库的逻辑表示顺序。下面分别展开说明:
SELECT product_id, product_name, purchase_price
FROM Product;
select select_expr,可进行数据库所支持的任何运算。
SELECT *
FROM Product;
为字段取别名
MySQL可以指定列别名,替换字段或表达式。
列名 [AS] 列别名
select studentid as 学号,sname as 姓名,sex as 性别 from TStudent
select studentid 学号,sname 姓名,sex 性别 from TStudent
为表取别名
为了方便操作或者需要多次使用相同的表时,可以为表指定别名,用别名替代表原来的名称。
表名 [AS] 表别名
select a.studentid 学号,a.sname 姓名,a.sex 性别 from TStudent as a;
select a.studentid 学号,a.sname 姓名,a.sex 性别 from TStudent a;
再比如:
SELECT product_id AS id,
product_name AS name,
purchase_price AS “价格”
FROM Product;
SELECT ‘2009-02-24’ AS date, product_id, product_name
FROM Product;
在SELECT语句中可以使用DISTINCE关键字指示MySQL消除重复的记录值。
SELECT DISTINCT 字段名 FROM 表名;
SELECT DISTINCT product_type
FROM Product;
SELECT product_name, product_type
FROM Product;
WHERE product_type = '衣服';
语法:
select select_expr
case
when 条件1 then 表达式1
when 条件2 then 表达式2
...
else 表达式
end [as]column_alias
如:查询表custormers中客户的cust_name和cust_sex,判断结果集中cust_sex列,若为‘M’则输出‘男’,否则输出‘女’,同时将cust_sex列显示为“性别”
select cust_name,
case
when cust_sex = 'M' as '男'
else '女'
end as '性别'
form mysql_test.customers;
再比如:
SELECT product_name,
CASE WHEN product_type = '衣服'
THEN CONCAT('A:', product_type)
WHEN product_type = '办公用品'
THEN CONCAT('B:', product_type)
WHEN product_type = '厨房用具'
THEN CONCAT('C:',product_type)
ELSE NULL
END AS abc_product_type
FROM Product;
查询满足指定范围内的条件(其实是一个枚举表)的记录,使用IN操作符,将所有检索条件用括号括起来,检索条件用逗号分隔开,只要满足条件范围内的一个值即为匹配项。
查新姓 王 刘 石的学生
select * from TStudent where left(sname,1) in ('王','刘','石');
再比如:
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price IN (320, 500, 5000);
也可以用NOT IN
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price NOT IN (320, 500, 5000);
注意:在使用IN 和NOT IN 时是无法选取出NULL 数据的。
使用子查询作为IN谓词的参数:
SELECT product_name, sale_price
FROM Product
WHERE product_id IN (SELECT product_id
FROM ShopProduct
WHERE shop_id = '000C');
注:子查询,也就是所说的“嵌套”,题四问,就是要求用嵌套来实现
mysql区分四类子查询:
使用in子查询:这里的子查询只返回一列数据,数据列里的值将提供给外层查询语句进行比较操作。
语法: expression [not] in (subquery)
subquery:指子查询
expression:用于指定表达式,当表达式与子查询中返回的结果集中的某个值相等时,会返回true,否则返回false.
如:查询成绩高于80的学生的学号与姓名
select studentNo,studentName
from tb_student
where studentNo in (select studentNo from tb_score where score>80);
使用比较运算符子查询,将表达式的值与子查询结果进行比较运算
语法:
expression {= | < | <= | > | >= | <=> | <> | !=} {all | some | any}(subquery)
all,some,any:用于指定对比较运算的限制,all指对结果每个值都进行比较,都满足关系时会返回true
som,any是同义词,表示只要与结果的某个值相等就返回true.
如:
select from TStudent
where studentid=any (select distinct studentid from TScore where mark>98);
等价于:
select from TStudent
where studentid in (select distinct studentid from TScore where mark>98);
再比如:子查询查出考试成绩大于98的学生的studentid
select from TStudent
where studentid>some (select distinct studentid from TScore where mark>98)
使用exist的子查询,主要判断子查询结果集是否为空
系统对子查询进行运算以判断子查询是否返回行,如果至少返回一行,那么EXISTS的结果为true,此时外层查询语句将进行查询;如果子查询没有返回任何行,那么EXISTS返回的结果是false,此时外层语句将不进行查询。
语法:
exist (subquery) --不为空返回true,如:
SELECT product_name, sale_price
FROM Product AS P
WHERE EXISTS (SELECT *
FROM ShopProduct AS SP
WHERE SP.shop_id = '000C'
AND SP.product_id = P.product_id);
再比如:查询学号为01001同学信息,还有成绩。
select from TStudent
where studentid='01001'
and exists (select from TScore where studentid='01001');
查询某个范围内的值,该操作符需要两个参数,即范围的开始值和结束值,如果字段值满足指定的范围查询条件,则这些记录被返回。
以下查询条件,查询学号100到150的学生,包括100和150
select from TStudent where convert(studentid,signed) between 100 and 150
等价于
select from TStudent where convert(studentid,signed)>=100
and convert(studentid,signed)<=150
自动转换类型
select * from TStudent where studentid between 100 and 150
百分号通配符‘%’,匹配任意长度的字符,甚至包括零字符
下划线通配符‘_’,一次只能匹配任意一个字符
查找姓名中间字为“志”字的学生
select from TStudent where sname like '志' ;
查找姓名中有“志”字的学生
select from TStudent where sname like '%志%';
前方一致查询:
SELECT *
FROM SampleLike
WHERE strcol LIKE 'ddd%';
也可用_(下划线)代替%,但_只能代表一个字符
SELECT *
FROM SampleLike
WHERE strcol LIKE 'abc_';
中间一致查询:
SELECT *
FROM SampleLike
WHERE strcol LIKE '%ddd%';
后方一致查询:
SELECT *
FROM SampleLike
WHERE strcol LIKE '%ddd';
在SELECT语句中使用IS NULL子句,可以查询某字段内容为空记录。
为了选取出某些值为NULL 的列的数据,不能使用=,而只能使用特定的谓词IS NULL
语法:
expressions is [not] null
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price IS NULL;
查找邮箱是空值的记录
select * from s where email is null;
使用AND连接两个甚至多个查询条件,多个条件表达式之间用AND分开。
select * from TStudent where sex='男' and Class='net' and studentid>20 and studentid<50;
OR操作符,表示只需要满足其中一个条件的记录即可返回。OR也可以连接两个甚至多个查询条件,多个条件表达式之间用AND分开。
select * from TStudent where sname like '%志%' or class='net';
语法:
limit {[offset,] row_count | row_count offset offset}
offset:可选项,默认数字为0,指定第一行在查询结果中的位置(从哪个列开始输出)。
row_count:返回数据的行数。
row_count 关键字offset offset:从第offset+1行开始,取row_countt行。
LIMIT关键字可以返回指定位置的记录。
LIMIT [位置偏移量,] 行数
返回前10个学生
select from TStudent limit 10;
返回第11-20个学生,偏移量是10,就意味着从第11个开始取10条记录。
select from TStudent limit 10,10;
再比如:
select *
from user
where username='xiaomin'
order by user_id DESC
limit 1 offset 2 或者 limit 2,1
'order by user_id DESC' :根据 user_id 倒序排列。如果没有 DESC 表示正序排列
'limit' : 设定返回的记录数
'offset' : 设定查询时偏移个数,默认为0。
问题:
LIMIT 2,1
LIMIT 1 OFFSET 2
这两个语句为什么表达的意思是一样的呢?
解答:
记住三点:
1.在计算机中索引都是从0开始的。但是LIMIT、OFFSET后面的数字只表示个数,和索引没有关系。
2.一般涉及到偏移参数(偏移3行),这样的描述都不包含所描述的那个个数,即3行数据已经不在“视野”内,偏移到“视野外”了,看不见,自然就不包含了。
3.一般涉及到索引参数(截取索引3到索引5),这样的描述包含索引2,不包含索引5
LIMIT 2,1 : 表示偏移2行数据,获取1个数据。即获取的是第3行数据
LIMIT 1 OFFSET 2 : 表示获取1个数据,但是偏移2行数据,即获取的也是第3行数据
正则表达式作用是匹配文本,将一个模式(正则表达式)与一个文本串进行比较。MySQL用WHERE子句对正则表达式提供了初步的支持,允许指定用正则表达式过滤SELECT检索出的数据。
在SQL查询语句中,查询条件REGEXP后所跟的东西作为正则表达式处理。
查询以特定字符或字符串开头的记录
字符‘^’匹配以特定字符或者字符串开头的文本。
select * from TStudent where sname regexp '^刘平';
查询以特定字符或字符串结尾的记录
字符‘$’匹配以特定字符或者字符串结尾的文本。
select * from TStudent where cardid regexp '36$';
用符号"."来替代字符串中的任意一个字符
字符‘.’匹配任意一个字符。
select * from TStudent where sname regexp '.康.';
使用"*"和"+"来匹配多个字符
星号‘’匹配前面的字符任意多次,包括0次。
加号‘+’匹配前面的字符至少一次。
找出×××以19开始,以6结束的学生
select from TStudent where cardid regexp '^19.6$'
找出×××号中有123的学生
select from TStudent where cardid regexp '.123+.';
匹配指定字符串
正则表达式可以匹配指定字符串,只要匹配字符串在查询文本中即可,如要匹配多个字符串,多个字符串之间使用分隔符‘|’隔开。
select * from TStudent where sname regexp '武|尹|罗';
匹配指定字符中的任意一个
方括号“[]”指定一个字符集合,只匹配其中任何一个字符,即为所查找的文本。不支持汉字。
select from TStudent where email regexp '[w-z]';
select from TStudent where cardid regexp '^[1-3,7]';
匹配指定字符以外的字符
“[^字符集合]”匹配不在指定集合中的任何字符。
select * from TStudent where cardid regexp '^[^1-7]';
使用{M}或者{M,N}来指定字符串连续出现的次数
“字符串{n,}”表示至少匹配n次前面的字符。“字符串{n,m}”表示匹配前面的字符串不少于n次,不多于m次。
查找×××中出现138并且后面有8位0-9的数字的学生。
select * from TStudent where cardid regexp '138[0-9]{15}';
利用UNION关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集。合并时,两个表对应的列数和数据类型必须相同。各个SELECT语句之间使用UNION(联盟)或UNION ALL关键字分隔。
要求第一个SQL语句返回的列和第二条返回的列数相同,
select studentid,sname from TStudent where studentid<=10
union
select studentid, sname from TStudent where sname like '王%';
作用为:将结果集中的数据行按照列的值进行逻辑分组,指示对分组进行操作,而不再是整个结果集。
语法:
group by {col_name | expr | position }[asc|desc],... [with rollup]
col_name:r指定选择分组的列,列必须是select选择中的列
expr:用于分组表达式,通常与聚合函数一块使用,如下,用count(*)
position:选择列在结果集中的位置。
rollup:卷起,with rollup:可得到每个分组及整体的汇总行
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type;
再如:在customers中获取包含相同地址的男性客户数和女性客户人数:
select cus_addr,cus_sex,count(*) as '人数'
from mysql_test.customers
group by cus_addr,cus_sex;
如要求获得相同地址的男性客户数、女性客户数、总客户数、总人数:只要在以上SQL语句,加上with rollup
group by 再理解之“用了之后会有什么效果呢?”
如字名,就是分组。select +后同就是分组的项(列)。那么分组的项肯定是select后面的项,要是有的项没在select后肯定是错的,但要是在聚合函数中,则是对的,因为聚合本身就代表分组与统计。
既然能进行分组,分组的项之间肯定是有某些规律的或符合一定的逻辑。什么逻辑或规律呢?要说逻辑,分组项(列)肯定是代表一类的记录(行),要说规律,分组项用聚合函数,统计汇总某类记录,那么一定是要用group by .
另外,写group by 时,一定要脑补出关系表的样子,不能想当然。
如以下实例:
select * from t_order;
+----+---------+---------------+-------+----------+
| id | user_id | user_name | price | the_year |
+----+---------+---------------+-------+----------+
| 1 | 1001 | 路人甲Java | 11.11 | 2017 |
| 2 | 1001 | 路人甲Java | 22.22 | 2018 |
| 3 | 1001 | 路人甲Java | 88.88 | 2018 |
| 4 | 1002 | 刘德华 | 33.33 | 2018 |
| 5 | 1002 | 刘德华 | 12.22 | 2018 |
| 6 | 1002 | 刘德华 | 16.66 | 2018 |
| 7 | 1002 | 刘德华 | 44.44 | 2019 |
| 8 | 1003 | 张学友 | 55.55 | 2018 |
| 9 | 1003 | 张学友 | 66.66 | 2019 |
+----+---------+---------------+-------+----------+
9 rows in set (0.00 sec)
单字段分组
SELECT
user_id 用户id, COUNT(id) 下单数量
FROM
t_order
GROUP BY user_id;
+----------+--------------+
| 用户id | 下单数量 |
+----------+--------------+
| 1001 | 3 |
| 1002 | 4 |
| 1003 | 2 |
+----------+--------------+
3 rows in set (0.00 sec)
多字段分组
SELECT
user_id 用户id, the_year 年份, COUNT(id) 下单数量
FROM
t_order
GROUP BY user_id , the_year;
+----------+--------+--------------+
| 用户id | 年份 | 下单数量 |
+----------+--------+--------------+
| 1001 | 2017 | 1 |
| 1001 | 2018 | 2 |
| 1002 | 2018 | 3 |
| 1002 | 2019 | 1 |
| 1003 | 2018 | 1 |
| 1003 | 2019 | 1 |
+----------+--------+--------------+
6 rows in set (0.00 sec)
分组前筛选数据使用where
需要查询2018年每个用户下单数量,输出:用户id、下单数量,如下:
SELECT
user_id 用户id, COUNT(id) 下单数量
FROM
t_order t
WHERE
t.the_year = 2018
GROUP BY user_id;
+----------+--------------+
| 用户id | 下单数量 |
+----------+--------------+
| 1001 | 2 |
| 1002 | 3 |
| 1003 | 1 |
+----------+--------------+
3 rows in set (0.00 sec)
注:
Having与Where的区别
分组后筛选数据使用having
查询2018年订单数量大于1的用户,输出:用户id,下单数量,如下:
SELECT
user_id 用户id, COUNT(id) 下单数量
FROM
t_order t
WHERE
t.the_year = 2018
GROUP BY user_id
HAVING count(id)>=2;
+----------+--------------+
| 用户id | 下单数量 |
+----------+--------------+
| 1001 | 2 |
| 1002 | 3 |
+----------+--------------+
2 rows in set (0.00 sec)
分组后排序
获取每个用户最大金额,然后按照最大金额倒序,输出:用户id,最大金额,如下:
SELECT
user_id 用户id, max(price) 最大金额
FROM
t_order t
GROUP BY user_id
ORDER BY 最大金额 desc;
+----------+--------------+
| 用户id | 最大金额 |
+----------+--------------+
| 1001 | 88.88 |
| 1003 | 66.66 |
| 1002 | 44.44 |
+----------+--------------+
3 rows in set (0.00 sec)
获取每个用户下单的最大金额及下单的年份,输出:用户id,最大金额,年份,正确的写法,如下:
SELECT
user_id 用户id,
price 最大金额,
the_year 年份
FROM
t_order t1
WHERE
(t1.user_id , t1.price)
IN
(SELECT
t.user_id, MAX(t.price)
FROM
t_order t
GROUP BY t.user_id);
+----------+--------------+--------+
| 用户id | 最大金额 | 年份 |
+----------+--------------+--------+
| 1001 | 88.88 | 2018 |
| 1002 | 44.44 | 2019 |
| 1003 | 66.66 | 2019 |
+----------+--------------+--------+
3 rows in set (0.00 sec)
建议:在写分组查询的时候,最好按照标准的规范来写,select后面出现的列必须在group by中或者必须使用聚合函数。
having:过滤分组:规则包含哪些分组,排除哪些分组
语法:
having where_condition
注:聚合函数只能出现在SELECT列表、HAVING子句和ORDER BY子句中
例如:
查找,列出相同地址的客户人数少于3的所有的客户姓名及对应的地址
select cus_name,cus_addr
from mysql_test.customers
group by cus_addr,cus_name
having count(*)<=3;
再比如:查询平均分大于80的学生
select concat(a.StudentID,' ',a.sname) ss,avg(b.mark) m
from TStudent a join TScore b
on a.StudentID=b.StudentID
group by ss having m>80;
使用聚合函数查询例子:
COUNT()函数
select class,COUNT(*) from TStudent group by class;
SUM()函数
查询每个学生总分
select concat(a.StudentID,' ',a.sname) ss,SUM(b.mark)
from TStudent a join TScore b on a.StudentID=b.StudentID
group by ss;
AVG()函数
统计每个班平均分
Select class,AVG(mark)
from TStudent a join TScore b on a.StudentID=b.StudentID
group by class;
多字段分组
统计每班每科平均分,需要按两列分组class和subJectName
select class,subJectName,AVG(mark)
from TStudent a join TScore b on a.StudentID=b.StudentID
join TSubject c on b.subJectID=c.subJectID
group by class,subJectName;
GROUP BY和WHERE并用时SELECT语句的执行顺序:
FROM → WHERE → GROUP BY → SELECT
SELECT purchase_price, COUNT(*)
FROM Product
WHERE product_type = '衣服'
GROUP BY purchase_price;
语法:
order by {col_name | expr | position }[asc|desc],...
含义与group by 后相同,不再重复。
不同点:
例如:查找平均分大于80分,按平均分排序。
select concat(a.StudentID,' ',a.sname) ss,avg(b.mark) m
from TStudent a join TScore b
on a.StudentID=b.StudentID
group by ss having m>80 order by m;
再如书上例子:在customers表中,按照姓名和地址降序排列,输出客户姓名和性别
select cus_name,cus_sex
from mysql.customers
order by cus_name desc,cus_addr desc;
子句的书写顺序
SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY
SELECT product_id, product_name, sale_price, purchase_price
FROM Product
ORDER BY sale_price;
SELECT product_id, product_name, sale_price, purchase_price
FROM Product
ORDER BY sale_price DESC;
注意:默认升序
算数运算符和比较运算符
加 +
减 -
乘 *
除 /
注意:所有包含NULL 的计算,结果肯定是NULL。
SELECT product_name, sale_price, sale_price * 2 AS "sale_price_x2"
FROM Product;
等于 =
不等于 <>
大于 >
大于等于 >=
小于 <
小于等于 <=
SELECT product_name, product_type, regist_date
FROM Product
WHERE regist_date < '2009-09-27';
SELECT product_name, sale_price, purchase_price
FROM Product
WHERE sale_price - purchase_price >= 500;
注意:不能对NULL使用比较运算符,正确的方法是:
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price IS NULL;
逻辑运算符(NOT、AND、OR)
SELECT product_name, product_type, sale_price
FROM Product
WHERE NOT sale_price >= 1000;
(也就是sale_price<1000)
AND运算符在其两侧的查询条件都成立时整个查询条件才成立,其意思相当于“并且”。
SELECT product_name, purchase_price
FROM Product
WHERE product_type = '厨房用具'
AND sale_price >= 3000;
运算符在其两侧的查询条件有一个成立时整个查询条件都成立,其意思相当于“或者”。
SELECT product_name, purchase_price
FROM Product
WHERE product_type = '厨房用具'
OR sale_price >= 3000;
对表进行聚合查询
常用的五个聚合函数:
SELECT COUNT(*)
FROM Product;
SELECT COUNT(purchase_price)
FROM Product;
SELECT COUNT(DISTINCT product_type)
FROM Product;
(所有的聚合函数都可以使用DISTINCT)
SELECT MAX(regist_date), MIN(regist_date)
FROM Product;
内连接查询,最常用的连接类型。内连接也是默认的表连接。
内连接(INNER JOIN)使用比较运算符根据每个表共有的列的值匹配两个表中的行,并列出表中与连接条件相匹配的数据行,组合成新的记录。在内连接查询中,只有满足条件的记录才能出现在结果关系中。
语法:
select some_columns
from table1
inner join
table2
on some_conditions;
some_columns:用于指定需要检索的列名。
some_conditions:两张表按什么条件进行连接。[
隐式的内连接,没有INNER JOIN,形成的中间表为两个表的笛卡尔积。
select a.StudentID, a.Sname, b.mark from TStudent a, TScore b
where a.StudentID=b.StudentID;
显示的内连接,一般称为内连接,有INNER JOIN,形成的中间表为两个表经过ON条件过滤后的笛卡尔积。
select a.StudentID, a.Sname, b.mark
from TStudent a inner join TScore b
on a.StudentID=b.StudentID;
select a.StudentID,a.Sname,c.subJectName,b.mark
from TStudent a join TScore b
on a.StudentID=b.StudentID join TSubject c
on b.subJectID=c.subJectID;
效果:
如果某列只在一张表中,就可以不用指明是哪个表中的列。
select a.StudentID,a.Sname,subJectName,mark
from TStudent a join TScore b on a.StudentID=b.StudentID
join TSubject c on b.subJectID=c.subJectID;
再比如:使用等值连接
SELECT SP.shop_id, SP.shop_name, SP.product_id, P.product_name, P.sale_price
FROM ShopProduct AS SP INNER JOIN Product AS P
ON SP.product_id = P.product_id;
像这样使用联结运算将满足相同规则的表联结起来时,WHERE、GROUP BY、HAVING、ORDER BY 等工具都可以正常使用.
再比如:
连接两张表,只返回满足条件的数据。
user 表和 permission表:
select user.name , permission.type from user
join permission on permission.id = user.id
外连接查询
外连接分为左连接、右连接、全连接。外连不但返回符合连接和查询条件的数据行,还返回不符合条件的一些行。外连接分三类:左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)和全外连接(FULL OUTER JOIN)。
三者的共同点是都返回符合连接条件和查询条件(即:内连接)的数据行。不同点如下:
左外连接还返回左表中不符合连接条件及符合查询条件的数据行。
右外连接还返回右表中不符合连接条件及符合查询条件的数据行。
全外连接还返回左表中不符合连接条件及符合查询条件的数据行,并且还返回右表中不符合连接条件单符合查询条件的数据行。全外连接实际是上左外连接和右外连接的数学合集(去掉重复),即“全外=左外 UNION 右外”。
左连接
包含左边表的全部行(不管右边的表中是否存在与它们匹配的行),以及右边表中全部匹配的行。
左连接的结果集包括 LEFT OUTER子句中指定的左表的所有行,而不仅仅是连接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。
select a.StudentID, a.Sname, b.mark from TStudent a left join TScore b on a.StudentID=b.StudentID;
再比如:
user 表和 permission表:
select user.name , permission.type from user
left join permission on permission.id = user.id
两个表:
SELECT SP.shop_id, SP.shop_name, SP.product_id, P.product_name, P.sale_price
FROM ShopProduct AS SP LEFT OUTER JOIN Product AS P ①
ON SP.product_id = P.product_id;
三个以上表:
SELECT SP.shop_id, SP.shop_name, SP.product_id, P.product_name, P.sale_price, IP.inventory_quantity
FROM ShopProduct AS SP INNER JOIN Product AS P ①
ON SP.product_id = P.product_id
INNER JOIN InventoryProduct AS IP ②
ON SP.product_id = IP.product_id
WHERE IP.inventory_id = 'P001';
右连接:
右连接包含右边表的全部行(不管左边的表中是否存在与它们匹配的行),以及左边表中全部匹配的行。
右连接是左连接的反向连接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
select a.StudentID, a.Sname, b.mark from TScore b right join TStudent a on a.StudentID=b.StudentID;
全连接:
全连接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。MySQL不支持全外连接。可以通过左外和右外求合集来获取全外连接的查询结果。
select a.StudentID, a.Sname, b.mark from TStudent a left join
TScore b on a.StudentID=b.StudentID
union
select b.StudentID, c.subJectName, b.mark from TScore b right join
TSubject c on b.subJectID=c.subJectID;
交叉连接
交叉连接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉连接有显式的和隐式的,不带ON子句,返回的是两表的乘积,也叫笛卡尔积。
FROM子句中的表或视图可通过内连接或全连接按任意顺序指定;但是,用左或右向外连接指定表或视图时,表或视图的顺序很重要。
隐式交叉连接,没有cross join
select a.StudentID, a.Sname, b.mark from TStudent a,TScore b where a.StudentID < 4;
显示交叉连接,有cross join
select a.StudentID, a.Sname, b.mark from TStudent a cross join TScore b where a.StudentID < 4;
表的加减法
SELECT product_id, product_name
FROM Product
UNION
SELECT product_id, product_name
FROM Product2;
通过UNION 进行并集运算时可以使用任何形式的SELECT 语句,WHERE、GROUP BY、HAVING 等子句都可以使用,但是ORDER BY 只能在最后使用一次。
注意:UNION会删去两个表中的重复记录。如果想保留重复记录,可以在UNION后面加ALL
MySQL不支持INTERSECT
MySQL不支持EXCEPT
新建两张表:
表1:student 截图如下:
表2:course 截图如下:
(此时这样建表只是为了演示连接SQL语句,当然实际开发中我们不会这样建表,实际开发中这两个表会有自己不同的主键。)
一、外连接
外连接可分为:左连接、右连接、完全外连接。
1、左连接 left join 或 left outer join
SQL语句:select * from student left join course on student.ID=course.ID
执行结果:
左外连接包含left join左表所有行,如果左表中某行在右表没有匹配,则结果中对应行右表的部分全部为空(NULL).
注:此时我们不能说结果的行数等于左表数据的行数。当然此处查询结果的行数等于左表数据的行数,因为左右两表此时为一对一关系。
2、右连接 right join 或 right outer join
SQL语句:select * from student right join course on student.ID=course.ID
执行结果:
右外连接包含right join右表所有行,如果左表中某行在右表没有匹配,则结果中对应左表的部分全部为空(NULL)。
注:同样此时我们不能说结果的行数等于右表的行数。当然此处查询结果的行数等于左表数据的行数,因为左右两表此时为一对一关系。
3、完全外连接 full join 或 full outer join
SQL语句:select * from student full join course on student.ID=course.ID
执行结果:
完全外连接包含full join左右两表中所有的行,如果右表中某行在左表中没有匹配,则结果中对应行右表的部分全部为空(NULL),如果左表中某行在右表中没有匹配,则结果中对应行左表的部分全部为空(NULL)。
二、内连接 join 或 inner join
SQL语句:select * from student inner join course on student.ID=course.ID
执行结果:
inner join 是比较运算符,只返回符合条件的行。
此时相当于:select * from student,course where student.ID=course.ID
三、交叉连接 cross join
1.概念:没有 WHERE 子句的交叉联接将产生连接所涉及的表的笛卡尔积。第一个表的行数乘以第二个表的行数等于笛卡尔积结果集的大小。
SQL语句:select * from student cross join course
执行结果:
如果我们在此时给这条SQL加上WHERE子句的时候比如SQL:select * from student cross join course where student.ID=course.ID
此时将返回符合条件的结果集,结果和inner join所示执行结果一样。
四、两表关系为一对多,多对一或多对多时的连接语句
当然上面两表为一对一关系,那么如果表A和表B为一对多、多对一或多对多的时候,我们又该如何写连接SQL语句呢?
其实两表一对多的SQL语句和一对一的SQL语句的写法都差不多,只是查询的结果不一样,当然两表也要略有改动。
比如表1的列可以改为:
Sno Name Cno
表2的列可以改为:
Cno CName
这样两表就可以写一对多和多对一的SQL语句了,写法和上面的一对一SQL语句一样。
下面介绍一下当两表为多对多的时候我们该如何建表以及些SQL语句。
新建三表:
表A: student 截图如下:
表B: course 截图如下:
表C: student_course 截图如下:
一个学生可以选择多门课程,一门课程可以被多个学生选择,因此学生表student和课程表course之间是多对多的关系。
当两表为多对多关系的时候,我们需要建立一个中间表student_course,中间表至少要有两表的主键,当然还可以有别的内容。
SQL语句:select s.Name,C.Cname from student_course as sc left join student as s on s.Sno=sc.Sno left join course as c on c.Cno=sc.Cno
执行结果:
此条SQL执行的结果是学生选课的情况。
SQL查询的原理
第一、单表查询:根据WHERE条件过滤表中的记录,形成中间表;然后根据SELECT的选择列选择相应的列进行返回最终结果。
第二、两表连接查询:对两表求积(笛卡尔积)并用ON条件和连接连接类型进行过滤形成中间表;然后根据WHERE条件过滤中间表的记录,并根据SELECT指定的列返回查询结果。实例如下:
select a.StudentID, a.Sname, b.mark
from TStudent a left join TScore b on a.StudentID=b.StudentID
where a.StudentID < 10;
第三、多表连接查询:先对第一个和第二个表按照两表连接做查询,然后用查询结果和第三个表做连接查询,以此类推,直到所有的表都连接上为止,最终形成一个中间的结果表,然后根据WHERE条件过滤中间表的记录,并根据SELECT指定的列返回查询结果。
过滤条件
ON条件:过滤两个连接表笛卡尔积形成中间表的约束条件。
WHERE条件:在有ON条件的SELECT语句中是过滤中间表的约束条件。在没有ON的单表查询中,是限制物理表或者中间查询结果返回记录的约束。在两表或多表连接中是限制连接形成最终中间表的返回结果的约束。
将WHERE条件移入ON后面是不恰当的。推荐的做法是ON只进行连接操作,WHERE只过滤中间表的记录。
连接查询的适用场景
连接查询是SQL查询的核心,连接查询的连接类型选择依据实际需求。如果选择不当,非但不能提高查询效率,反而会带来一些逻辑错误或者性能低下。两表连接查询选择方式的依据:
A、查两表关联列相等的数据用内连接。
B、Col_L是Col_R的子集时用右连接。
C、Col_R是Col_L的子集时用左连接。
E、 Col_R和Col_L彼此有交集但彼此互不为子集时候用全连接。
F、求差操作的时候用联合查询。
其他SQL语言要素:
A、字符常量
字符串常量使用单引号或双引号,数值常量不用加引号。
\n 换行
\’ 一个单引号
\” 一个双引号
\ 一个\ 如果没有转义字符 就认为\是一个转义字符
\% 一个% 如果没有转义字符就认为这是一个通配符
_ 一个 如果没有转移字符 就认为是一个通配符如果字符串常量中需要换行、有单引号、双引号 % \前面需要加转义字符 \
B、数值常量
数值常量不用添加引号,
select 100+100+200
C、布尔常量
布尔型常量取值 true 和 false
在SQL中使用1和0表示
select true,false
在表达式中
select 100>200
select 100<200
A、用户自定义变量使用@开始,使用set给变量赋值。
set @name='孙悟空';
select @name;
B、系统变量分为全局系统变量和会话系统变量。
全局系统变量:针对所有默认设置
会话系统变量:针对当前用户生效,用户登录MySQL会使用全局系统变量,如果会话中更改了变量值,使用更改后的值,不过只针对当前用户生效。
show variables 显示会话系统变量
show global variables 显示全局系统变量
show session variables 显示会话系统变量
show global variables like 'sql_select_limit';使用通配符显示匹配的变量设置
show session variables like 'sql_select_limit';系统变量使用@@标识
select @@global.sql_select_limit 查看某个全局系统变量设置
select @@session.sql_select_limit 查看某个会话系统变量设置
set @@session.sql_select_limit=2 设置会话系统变量
全局系统变量需要在/etc/my.cnf配置文件中修改。
1、数值类型
MySQL的数值数据类型只要分为整数和浮点数。
MySQL支持的5个主要整型是TINYINT,SMALLINT,MEDIUMINT,INT和 BIGINT。
MySQL 以一个可选的显示宽度指示器的形式对 SQL 标准进行扩展,这样当从数据库检索一个值时,可以把这个值加长到指定的长度。例如,指定一个字段的类型为 INT(6),就可以保证所包含数字少于 6个的值从数据库中检索出来时能够自动地用空格填充。需要注意的是,使用一个宽度指示器不会影响字段的大小和它可以存储的值的范围。
如果对一个字段存储了一个超出许可范围的数字,MySQL会根据允许范围最接近的一端截短后再进行存储。MySQL会在不合规定的值插入表前自动修改为0。
UNSIGNED 修饰符规定字段只保存正值。因为不需要保存数字的正、负符号,可以在储时节约一个“位”的空间。从而增大字段可以存储的值的范围。
ZEROFILL修饰符规定0可以用来真补输出的值,可以阻止MySQL数据库存储负值。
应用实例:
create table tint
(
tid tinyint,
tid2 tinyint unsigned,
tid3 int(5)
)
alter table tint modify column tid3 int(5) zerofill
insert into tint values (21,23,4)
insert into tint values (11,21,233322)
如果存储的数据溢出显示警告
insert into tint values (221,-23,4)
show warnings
查看当前操作的警告信息
FLOAT、DOUBLE和DECIMAL类型
MySQL支持的三个浮点类型是FLOAT、DOUBLE和DECIMAL类型。FLOAT数值类型用于表示单精度浮点数值,而DOUBLE数值类型用于表示双精度浮点数值,
附加参数是一个显示宽度指示器和一个小数点指示器。比如语句FLOAT(7,3)规定显示的值不会超过7位数字,小数点后面带有3位数字。
对于小数点后面的位数超过允许范围的值,MySQ 会自动将它四舍五入为最接近它的值,再插入它。
DECIMAL数据类型用于精度要求非常高的计算中,允许指定数值的精度和计数方法作为选择参数。精度在这里指为这个值保存的有效数字的总个数,而计数方法表示小数点后数字的位数。比如语句DECIMAL(7,3)规定了存储的值不会超过 7位数字,并且小数点后不超过3位。
忽略DECIMAL数据类型的精度和计数方法修饰符将会使MySQL数据库把所有标识为这个数据类型的字段精度设置为 10,计算方法设置为 0。
UNSIGNED和ZEROFILL修饰符也可以被FLOAT、DOUBLE和DECIMAL数据类型使用。
2、字符串类型
MySQL提供了8个基本的字符串类型,可以存储的范围从简单的一个字符到巨大的文本块或二进制字符串数据。
CHAR类型用于定长字符串,并且必须在圆括号内用一个大小修饰符来定义。大小修饰符的范围从0-255。比指定长度大的值将被截短,而比指定长度小的值将会用空格作填补。
CHAR类型可以使用BINARY修饰符。当用于比较运算时,BINARY修饰符使CHAR以二进制方式参于运算,而不是以传统的区分大小写的方式。
CHAR类型的一个变体是VARCHAR类型,是一种可变长度的字符串类型,并且也必须带有一个范围在0-255之间的指示器。CHAR和VARCHGAR不同之处在于MySQL数据库处理范围指示器的方式:CHAR把范围大小视为值的大小,在长度不足的情况下就用空格补足;而VARCHAR类型把范围指示器视为最大值并且只使用存储字符串实际需要的长度(增加一个额外字节来存储字符串本身的长度)来存储值。短于指示器长度的VARCHAR类型不会被空格填补,但长于指示器的值仍然会被截短。
因为VARCHAR类型可以根据实际内容动态改变存储值的长度,所以在不能确定字段需要多少字符时使用VARCHAR类型可以大大地节约磁盘空间、提高存储效率。
VARCHAR类型在使用BINARY修饰符时与CHAR类型完全相同。
对于字段长度要求超过255个的情况下,MySQL提供了TEXT和BLOB两种类型。根据存储数据的大小,都有不同的子类型。大型的数据用于存储文本块或图像、声音文件等二进制数据类型。
TEXT和BLOB类型在分类和比较上存在区别。BLOB类型区分大小写,而TEXT 不区分大小写。大小修饰符不用于各种BLOB和TEXT子类型。比指定类型支持的最大范围大的值将被自动截短。
3、日期和时间类型
在处理日期和时间类型的值时,MySQL带有5个不同的数据类型可供选择。分为简单日期、时间类型,混合日期、时间类型。根据要求的精度,子类型在每个分类型中都可以使用,并且MySQL带有内置功能可以把多样化的输入格式变为一个标准格式。
MySQL用DATE和YEAR类型存储简单的日期值,使用TIME类型存储时间值。日期、时间类型可以描述为字符串或不带分隔符的整数序列。如果描述为字符串,DATE类型的值应该使用连字号作为分隔符分开,而TIME类型的值使用冒号作为分隔符分开。没有冒号分隔符的TIME类型值,将会被MySQL理解为持续的时间,而不是时间戳。
MySQL还对日期的年份中的两个数字的值,或是SQL语句中为YEAR类型输入的两个数字进行最大限度的通译。因为所有YEAR类型的值必须用4个数字存储。MySQL试图将2个数字的年份转换为4个数字的值。把在00-69范围内的值转换到2000-2069范围内。把70-99范围内的值转换到1970-1979之内。如果 MySQL自动转换后的值并不符合需要,请输入4个数字表示的年份。
除了日期和时间数据类型,MySQL还支持DATETIME和TIMESTAMP混合类型,可以把日期和时间作为单个的值进行存储。通常用于自动存储包含当前日期和时间的时间戳,并可在需要执行大量数据库事务和需要建立一个调试和审查用途的审计跟踪的应用程序中发挥良好作用。
如果对TIMESTAMP类型的字段没有明确赋值,或是被赋与了null值。MySQL 会自动使用系统当前的日期和时间来填充它。
create table dd
(
d DATE,
t TIME,
y YEAR,
dt DATETIME,
ts timestamp
)
insert into dd values ('2015-11-05','15:48:34','2015',
'2015-11-05 15:48:34','2015-11-05 15:48:34')
不满足时间格式的,插入后变成
insert into dd values ('201511-05','15:78:34','15',
'2015-11-05 154834','2015-11-05 15:48:34')
4、复合类型
MySQL支持两种复合数据类型ENUM和SET,属于扩展SQL规范。一个ENUM 类型只允许从一个集合中取得一个值;而SET类型允许从一个集合中取得任意多个值。
ENUM类型
ENUM类型只允许在集合中取得一个值。ENUM类型字段可以从集合中取得一个值或使用null值,如果输入不在集合中的值将会使MySQL插入一个空字符串。另外如果插入值的大小写与集合中值的大小写不匹配,MySQL会自动使用插入值的大小写转换成与集合中大小写一致的值。
ENUM类型在系统内部可以存储为数字,并且从1开始用数字做索引。一个 ENUM类型最多可以包含65536个元素,其中一个元素被MySQL保留,用来存储错误信息,错误值用索引0或者一个空字符串表示。
MySQL认为ENUM类型集合中出现的值是合法输入,除此之外其它任何输入都将失败。通过搜索包含空字符串或对应数字索引为0的行就可以很容易地找到错误记录的位置。
SET类型
SET类型可以从预定义的集合中取得任意数量的值,任何试图在SET类型字段中插入非预定义的值都会使MySQL插入一个空字符串。如果插入一个即有合法的元素又有非法的元素的记录,MySQL将会保留合法的元素,除去非法的元素。
一个SET类型最多可以包含64项元素。在SET元素中值被存储为一个分离的“位”序列,SET类型中不可能包含两个相同的元素。
从SET类型字段中找出非法的记录只需查找包含空字符串或二进制值为0的行。
create table dd
(
sname char(10),
sex enum('男','女'),
hobby set('游泳','旅游','打球')
);
insert into dd values ('韩立刚','男','游泳,打球');
insert into dd values ('张京','难','看电影,打球');
插入一条有错误的记录,sex列没有插入成功,hobby列只能插入set中列出的值
1、算术运算符
算术运算符包括:加(+)、减(-)、乘()、除(/)、取模(%)。
select 4+3,5-3,58,20/4;
select 17%5;
select sid,sname,age+2 from s;
2、比较运算符
比较运算符包括等于(=)、大于(>)、小于(<)、大于等于(>=)、小于等于(<=)、不等于(!=或<>)
select 10=10,10<10,10<>10;
select binary 'a'='A','a'<'b';比较字符的二级制
select from s where sid<=2;
select from s where sname='孙悟空';
3、逻辑运算符
逻辑运算符包括与(and或&&)、或(or或||)、非(not或!)。
逻辑运算符的应用举例
select from s where sname like '杨%' and age>40;
select from s where sname like '孙%' && age>30;
select from s where sname like '孙%' or sid<2;
select from s where sname like '孙%' || sid<2;
select from s where not sname like '孙%';
select from s where !(sname like '孙%');
4、运算符优先级
算术运算符优先级:先乘除,后加减,括号优先
逻辑运算符优先级:先与操作,再或操作,括号优先
sname like '韩%' and age>40 or sid<3;
sname like '韩%' and (age>40 or sid<3);
5、表达式
表达式是常量、变量、运算符、函数等的组合。
1+2;
‘a’<’A’;
select * from s where age+4>40;
6、系统内置函数
函数大致可以分为以下几种。
ABS (数值) —— 绝对值
MOD (被除数, 除数) —— 求余
ROUND (对象数值, 保留小数的位数) —— 四舍五入
CONCAT (字符串1, 字符串2, 字符串3) —— 拼接
LENGTH (字符串) —— 字符串长度
LOWER (字符串) —— 小写
UPPER (字符串) —— 大写
REPLACE (对象字符串,替换前的字符串,替换后的字符串) —— 替换
SUBSTRING(对象字符串 FROM 截取的起始位置 FOR 截取的字符数)—— 截取
CURRENT_DATE —— 当前日期
CURRENT_TIME —— 当前时间
CURRENT_TIMESTAMP —— 当前的日期和时间
EXTRACT (日期元素 FROM 日期)
CAST(转换前的值 AS 想要转换的数据类型)—— 类型转换
COALESCE (数据1,数据2,数据3……) —— 将NULL转换为其他值
A、数学函数
ABS(x)
返回x的绝对值
select * from student where abs(age-45)<=2
查找和45岁相差不超过两岁用户
CEIL(x),CEILING(x)
返回大于或等于x的最小整数(向上取整)
FLOOR(x)
返回小于或等于x的最大整数(向下取整)
select ceil(5.4),floor(5.6);
select sid,sname,floor(age/10)*10 from s;
RAND()
返回0~1的随机数
select floor(RAND()1000);
产生一个0-1000的随机整数
select ,RAND() random from s order by random;
使用随机函数随机排序查询结果
RAND(x)
返回0~1的随机数,种子x值相同时返回的随机数相同。
SIGN(x)
返回x的符号,x是负数、0、正数分别返回-1、0、1
PI()
返回圆周率
TRUNCATE(x,y)
返回数值x保留到小数点后y位的值
select sign(-4),sign(434);
select PI();
select truncate(4.5454,2);
select truncate(AVG(age),2) from s;
ROUND(x)
返回离x最近的整数(四舍五入)
ROUND(x,y)
保留x小数点后y位的值,但截断时要四舍五入
POW(x,y),POWER(x,y)
返回x的y次方
SQRT(x)
返回x的平方根
EXP(x)
返回自然常数e的x次方。
B、字符串函数
CHAR_LENGTH(s)
返回字符串s的字符数
LENGTH(s)
返回字符串s的占用的空间的大小。
select * from student where length(sname)/char_length(sname)!=3
找到姓名中有英文字符的学生
CONCAT(s1,s2,.....)
将字符串s1,s2等多个字符串合并为一个字符串
CONCAT_WS(x,s1,s2,....)
同COUCAT(s1,s2,.....),但是每个字符串之间要加上x
select concat('韩立刚','河北师大','网络工程师')
select CONCAT('学号',sid,'姓名',sname,'年龄',age) from s
select CONCAT_ws(' ','学号',sid,'姓名',sname,'年龄',age) from s
INSERT(s1,x,len,s2)
使用字符串s2替换s1的x位置开始长度为len的字符串
select insert('hanligang',4,2,'zhi')
select insert(sname,2,0,' ') from s
UPPER(s),UCASE(s)
将字符串s的所有字符都变成大写字母
LOWER(s),LCASE(s)
将字符串s的所有字符都变成小写字母
select upper('HanLigang')
select lower('HanLigang')
select Upper(sname) from s
LEFT(s,n)
返回字符串s的前n个字符
RIGHT(s,n)
返回字符串s的后n个字符
select left('孙悟空',1)
select right('孙悟空',2)
LPAD(s1,len,s2)
字符串s2来填充s1的开始处,使字符串长度达到len
RPAD(s1,len,s2)
字符串s2来填充s1的结尾处,使字符串长度达到len
select lpad('1',4,'0')
select lpad(sid,4,0) from s
select RPAD('HAN',10,'B')
LTRIM(s)
去掉字符串s开始处的空格
RTRIM(s)
去掉字符串s结尾处的空格
TRIM(s)
去掉字符串s开始处和结尾处的空格
TRIM(s1 FROM s)
去掉字符串s中开始处和结尾处的字符串s1
用法示例:
select char_length(LTRIM(' han '))
select RTRIM(' han ')
select char_length(RTRIM(' han '))
select char_length(TRIM(' han '))
insert into s values(10,' 张志敏',32)
select * from s
update s set sname=LTRIM(sname)
select TRIM('h' from 'hanliganghhhh')
REPEAT(s,n)
将字符串s重复n次
SPACE(n)
返回n个空格
REPLACE(s,s1,s2)
用字符串s2代替字符串s中的字符串s1
用法示例:
select repeat('han',4)
select sid,concat(left(sname,1),SPACE(sid),right(sname,2)) from s
select replace('han li gang',' ','_')
select replace('han li gang',' ','')
STRCMP(s1,s2)
如果s1小于s2,strcmp函数返回一个小于零的值。如果s1大于s2,函数返回一个大于零的值。如果两个字符串相等,函数就返回零。
SUBSTRING(s,n,len)
获取从字符串s中的第n个位置开始长度为len的字符串
POSITION (s1 IN s)
从字符串s中获取s1的开始位置
INSTR(s,s1)
从字符串s中获取s1的开始位置
应用实例:
select strcmp('han','wang')
select strcmp('hlg','han')
select strcmp('han','an')
select SUBSTRING('[email protected]',11,7)
select sid,SUBSTRING(sname,2,1) from s
select SUBSTRING('[email protected]',POSITION('@' IN '[email protected]')+1,11)
select RIGHT('[email protected]',char_length('[email protected]')-POSITION('@' IN '[email protected]'))
alter table s add email CHAR(40)
select * from s
update s set email='[email protected]' where sid=1
update s set email='[email protected]' where sid=2
update s set email='[email protected]' where sid=3;获取email字段中@后面的字符串,先截取邮箱字段的长度,在截取邮箱的@字符的位置,计算出邮箱@后面有多少字符,
SELECT RIGHT(email,CHAR_LENGTH(email)-POSITION('@' in email)) from s
SELECT RIGHT(email,CHAR_LENGTH(email)-INSTR(email,'@')) from s
C、日期和时间函数
Linux命令行查看:
clock
显示硬件时间
date
显示系统时间
date -s 11/03/15
更改系统日期
date -s 9:21:4
更改系统时间
hwclock --systohc
使用系统时间覆盖硬件时间
hwclock --hctosys
使用硬件时间覆盖系统时间
MySQL命令行查看:
curdate()
CURRENT_DATE()
获取系统当前日期
curtime()
CURRENT_TIME()
获取系统当前时间
CURRENT_TIMESTAMP()
LOCALTIME()
NOW()
获取系统当前日期和时间
应用实例:
给表s增加一列,数据类型timestamp 默认值是当前时间。
alter table s add stime TIMESTAMP default now();
select * from s
insert into s (sid,sname,age,email) values (11,'张东',34,'[email protected]')
将以前用户的stime列更改为当前时间
update s set stime=now() where sid<11
返回日期d中的月份值,范围是1~12
MONTH(d)
返回日期d中的月份名称,如january
MONTHNAME(d)
返回日期d是星期几,如Monday
DAYNAME(d)
返回日期d是星期几,1表示星期日,2表示星期1
DAYOFWEEK(d)
返回日期d是星期几,0表示星期一,1表示星期2
WEEKDAY(d)
计算日期d是本年的第几个星期,范围是0-53
WEEK(d)
计算日期d是本年的第几个星期,范围是1-53
WEEKOFYEAR(d)
计算日期d是本年的第几天
DAYOFYEAR(d)
计算日期d是本月的第几天
DAYOFMONTH(d)
返回日期d中的年份值
YEAR(d)
返回日期d是第几季度,范围1-4
QUARTER(d)
返回时间t中的小时值
HOUR(t)
返回时间t中的分钟值
MINUTE(t)
返回时间t中的秒钟值
SECOND(t)
应用实例:
select concat(year(now()),'年',month(now()),'月',DAY(now()),'日')
select CONCAT(year(stime),'年',month(stime),'月',DAY(stime),'日') from s
计算日期d1到d2之间相隔的天数
DATEDIFF(d1,d2)
计算开始日期d加上n天的日期
ADDDATE(d,n)
计算起始日期d加上一个时间段后的日期
ADDDATE(d, INTERVAL expr type)
计算起始时间t加上n秒的时间
ADDTIME(t,n)
应用实例:
select datediff(now(),'2015-2-3')
select ADDDATE(now(),-1050)
select ADDDATE(now(),1050)
select ADDDATE(now(), INTERVAL 1000000 SECOND)
select ADDDATE(now(), INTERVAL 1000000 hour)
select ADDDATE(now(), INTERVAL -10000 day)
select ADDDATE(now(), INTERVAL '10 3' DAY_HOUR)
select ADDDATE(now(), INTERVAL 3 year)
D、系统信息函数
系统信息函数用来查询MySQL数据库的系统信息。例如查询数据库的版本,查询数据的当前用户等。
VERSION()
返回数据库的版本号
CONNECTION_ID()
返回服务器的连接数,也就是到现在为止mysql服务的连接次数
DATABASE(),SCHEMA()
返回当前数据库名
USER()
返回当前用户的名称
CHARSET(str)
返回字符串str的字符集
COLLATION(str)
返回字符串str的字符排列方式
LAST_INSERT_ID()
返回最后生成的auto_increment值
E、加密解密函数
加密函数是MySQL中用来对数据进行加密的函数。
PASSWORD(str)
对字符串str进行加密
MD5(str)
对字符串str进行MD5加密
ENCODE(str,pswd_str)
使用字符串pswd_str来加密字符串str,加密结果是一个二进制数,必须使用BLOB类型来保存
DECODE(crypt_str,pswd_str)
解密函数,使用字符串pswd_str来为crypt_str解密
应用实例:
create table webuser
(
logon varchar(20),
pw VARCHAR(100)
);
insert into webuser values ('hanligang',md5('abc'));
insert into webuser values ('zhangql',md5('123'));
select from webuser where logon='hanligang' and pw=MD5('abc');
ALTER TABLE webuser
MODIFY COLUMN pw
BLOB(1);
insert into webuser values ('zhangjing',encode('abcd','91xueit'));
select logon,decode(pw,'91xueit') from webuser;
select from webuser where logon='zhangjing' and decode(pw,'91xueit')='abcd';
F、聚合函数
Count()
统计满足条件的记录数量
select count(*) from s
统计表中有多少条记录
select COUNT(email) from s
select COUNT(all email) from s
统计表中email列有多少条有值的记录,包括重复值
select COUNT(distinct email) from s
统计表中email列有多少条有值的记录 消除重复值
Sum() 统计总数
select SUM(age) from s where email is not null
Avg() 求平均值
select avg(age) from s where email is not null
Max() 求最大值
Min() 求最小值
select avg(age),MAX(age),MIN(age) from s
group_concat() 将满足条件的记录,显示成一行,使用逗号分开
select group_concat(sname) from s where sid<5
G、条件判断函数
IF(value,t,f) 如果value是true t 如果是false 返回值f
select sname,IF(age>40,'中年','青年') as age from s
ifnull(value1,value2) 如果value1不为空,返回value1,如果value1为空,返回value2
select sname,IFNULL(email,'没有邮箱') as 邮箱 from s
Case when value1 then result1 else default end
当value1值是true 返回result1,否则返回default值
select sname,case when age>40 then '中年' else '青年' end from s
Case expr when value1 then ‘result1’ when value2 then ‘result2’ when value3 then ‘result3’ else ‘result4’ end
根据expr表达式的值,返回不同的值
select sname, case floor(age/10) when 2 then '壮年' when 3 then '青年' else '中年' end from s
H:数据类型转换函数
类型转换函数主要是CAST(xxx AS 类型), CONVERT(xxx,类型)。可以转换的类型是有限制的,包括二进制、字符型、日期、时间、日期时间型、浮点数、整数、无符号整数。
select CAST('00033ad' as signed)
select CONVERT(44.334,signed)
select concat(CONVERT(44.334,char(10)),'3000')
类型自动推导转换
select '0033aa'+23
select CONCAT(123,'abc',123)
I:格式化函数:FORMAT();