查询模型
- 列就是变量,在每一行上,列的值都在变化
- where条件是表达式,在哪一行表达式为真,哪一行就取出来
- 查询结果集可以当成表看
1、熟练运算符in和not的用法
运算符 | 说明 |
---|---|
in | 某个集合内 |
between and | 某个范围内 |
not 或 ! | 逻辑非 |
like
里的_
匹配单一字符
2、where的注意事项
where 1; --all
where 0; --empty
比如
select * from tbname where 1>2; -- empty
3、广义投影
mysql> #取出商品价比市场价省的钱
mysql> select goods_id,goods_name,(market_price-shop_price) as discount from goods;
#这一列即是运算结果,术语为“广义投影”
#即把列看成变量,可以运算
#取出商品价比市场价省的钱,并且大于200
mysql> select goods_id,goods_name,(market_price-shop_price) as discount from goods where (market_price-shop_price) >200;
而不能这样 where discount >200,因为 where 字句只针对原表中的数据,而discount是已经查询出的结果,用`having`
4、面试题
把数字[20,29]改为20,[30,39]改为30
mysql> select * from mst;
+------+
| num |
+------+
| 1 |
| 13 |
| 25 |
| 27 |
| 29 |
| 32 |
| 35 |
| 35 |
| 45 |
| 46 |
+------+
10 rows in set (0.00 sec)
mysql> update mst set num=floor(num/10)*10 where num between 20 and 39;
把有前缀“诺基亚”的商品名改为“HTC”
mysql> select goods_id,goods_name,concat('HTC',substring(goods_name,4)) from goo
ds where goods_name like "诺基亚%";
+----------+---------------------+---------------------------------------+
| goods_id | goods_name | concat('HTC',substring(goods_name,4)) |
+----------+---------------------+---------------------------------------+
| 4 | 诺基亚N85原装充电器 | HTCN85原装充电器
|
| 9 | 诺基亚E66 | HTCE66 |
| 14 | 诺基亚5800XM | HTC5800XM |
| 32 | 诺基亚N85 | HTCN85 |
+----------+---------------------+---------------------------------------+
COUNT(expr)函数:
- COUNT(colname) 返回SELECT语句检索到的行中非NULL值的数目。 若找不到匹配的行,则COUNT() 返回 0 。
- COUNT(*) 返回检索行的包含 NULL值的数目
mysql> SELECT * from test_count;
+------+------+
| id | num |
+------+------+
| 1 | 1 |
| 2 | NULL |
| NULL | NULL |
+------+------+
mysql> select count(id) from test_count;
+-----------+
| count(id) |
+-----------+
| 2 |
+-----------+
mysql> select count(num) from test_count;
+------------+
| count(num) |
+------------+
| 1 |
+------------+
mysql> select count(*) from test_count;
+----------+
| count(*) |
+----------+
| 3 |
+----------+
mysql> select count(1) from test_count;
+----------+
| count(1) |
+----------+
| 3 |
+----------+
count(*)和count(1)区别
- 在MyISAM中,无区别。因为引擎内有个计数器在维护着行数,行数可直接统计出来
- 在innoDB中,用count(*)直接读取行数,效率很低,因为引擎会一行一行数一遍
GROUP
- 取数据第一次出现的行
#分类统计商品数量
mysql> select cat_id,sum(goods_number) from goods group by cat_id;
+--------+-------------------+
| cat_id | sum(goods_number) |
+--------+-------------------+
| 3 | 6 |
| 4 | 2 |
| 6 | 3 |
| 8 | 19 |
| 16 | 6 |
| 18 | 1 |
| 19 | 10 |
| 20 | 1 |
| 22 | 1 |
| 24 | 64 |
| 25 | 998 |
+--------+-------------------+
分析以下sql
mysql> select goods_id,sum(goods_number) from goods;
+----------+-------------------+
| goods_id | sum(goods_number) |
+----------+-------------------+
| 1 | 1111 |
+----------+-------------------+
该语句可以执行,并且把goods_id第一次出现的值取出来了。
对于sql标准来说,该语句是错误的,不能执行的,因为语意有问题。
但是mysql可以,因为这是它的一个特点,出于可移植性和规范性,不推荐这么写
严格来说,group by a,b,c
为列,则select的列只能在a,b,c
里选择,才没有语意矛盾
HAVING
- 表的数据
where - 查询出满足条件的行
计算函数,group - 结果集(广义投影)
having - 最终结果集
where 针对表,having针对结果集
#查询本店价与市场价省的钱,并且省钱大于200
mysql> select goods_id,goods_name,(market_price-shop_price) as discount from goo
ds
-> where 1
-> having discount > 200;
+----------+--------------+----------+
| goods_id | goods_name | discount |
+----------+--------------+----------+
| 1 | KD876 | 277.60 |
| 9 | 诺基亚E66 | 459.60 |
| 69 | 平衡车 | 399.79 |
| 14 | 诺基亚5800XM | 525.00 |
| 32 | 诺基亚N85 | 602.00 |
+----------+--------------+----------+
#查询积压货款超过1w的栏目及其积压的货款
mysql> select cat_id,sum(goods_number*shop_price) as m from goods
-> group by cat_id
-> having m > 10000;
+--------+-----------+
| cat_id | m |
+--------+-----------+
| 3 | 16636.00 |
| 25 | 996004.00 |
+--------+-----------+
练习题
//where-group-having
//查询挂科两门及两门以上的学员平均分
//(题目解释:学员全部科目的平均分,并且为挂机两门以上(包括两门)的科目)
+------+---------+-------+
| name | subject | score |
+------+---------+-------+
| 张三 | 数学 | 90 |
| 张三 | 语文 | 50 |
| 张三 | 地理 | 40 |
| 李四 | 语文 | 55 |
| 李四 | 政治 | 45 |
| 王五 | 政治 | 30 |
+------+---------+-------+
#求平均分=》筛选挂数
mysql> select name,avg(score),sum(score<60) as gks from result
-> group by name having gks>=2;
+------+------------+------+
| name | avg(score) | gks |
+------+------------+------+
| 张三 | 60.0000 | 2 |
| 李四 | 50.0000 | 2 |
+------+------------+------+
#筛挂科数=》求平均分
mysql> select name,avg(score) from result
-> where name in (select name from (select name,count(1) as gks from result where score<60 group by name having gks>=2) as temp)
-> GROUP BY name;
+------+------------+
| name | avg(score) |
+------+------------+
| 张三 | 60.0000 |
| 李四 | 50.0000 |
+------+------------+
2 rows in set (0.00 sec)
ORDER
- 排序对象:结果集
- 书写语法:order colname1 asc/desc,colname asc/desc…
- 排序优先级:左高右低
LIMIT
- 书写语法:limit [offset,],N
- offset:偏移量。及忽略前面的条目数
- N:查询的条目数
mysql> select goods_id,goods_name,cat_id,shop_price from goods
-> order by cat_id,shop_price desc
-> limit 2,3;
+----------+--------------+--------+------------+
| goods_id | goods_name | cat_id | shop_price |
+----------+--------------+--------+------------+
| 8 | 飞利浦9@9v | 3 | 399.00 |
| 14 | 诺基亚5800XM | 4 | 2625.00 |
| 1 | KD876 | 4 | 1388.00 |
+----------+--------------+--------+------------+
3 rows in set (0.00 sec)
子查询
- where型子查询:把内层查询结果作为外层查询的比较条件
如果 where 列=(内层sql),则内层sql返回的必是单行单列单个值
如果 where 列 in (内层sql),则内层sql只返回单列,可多行 - from型子查询:内层sql的查询结果,当成临时表,供外层sql再次查询
- exists型子查询:把外层查询结果拿到内层sql测试,如果成立,则取出
子句书写顺序和执行优先级:where => group => having => order => limit
练习题
//取出每个cat_id下最大的goods_id
mysql> select cat_id,goods_id from goods
-> order by cat_id,goods_id desc;
+--------+----------+
| cat_id | goods_id |
+--------+----------+
| 3 | 32 |
| 3 | 9 |
| 3 | 8 |
| 4 | 14 |
| 4 | 1 |
| 6 | 60 |
| 6 | 59 |
| 6 | 54 |
| 8 | 53 |
| 8 | 52 |
| 8 | 4 |
| 16 | 48 |
| 16 | 47 |
| 16 | 46 |
| 16 | 44 |
| 16 | 43 |
| 16 | 42 |
| 18 | 36 |
| 19 | 51 |
| 19 | 50 |
| 19 | 49 |
| 19 | 45 |
| 19 | 41 |
| 19 | 40 |
| 19 | 39 |
| 19 | 38 |
| 19 | 37 |
| 19 | 35 |
| 20 | 58 |
| 22 | 55 |
| 24 | 72 |
| 24 | 70 |
| 24 | 69 |
| 24 | 68 |
| 24 | 64 |
| 24 | 63 |
| 24 | 62 |
| 24 | 61 |
| 25 | 73 |
+--------+----------+
39 rows in set (0.00 sec)
1.WHERE型
SELECT
*
FROM
(
SELECT
cat_id,
goods_id,
goods_name
FROM
goods
ORDER BY
cat_id,
goods_id DESC
) AS temp
GROUP BY
cat_id
ORDER BY
cat_id;
2.FROM型
SELECT
cat_id,
goods_id,
goods_name
FROM
goods
WHERE
goods_id IN (
SELECT
max(goods_id)
FROM
goods
GROUP BY
cat_id
)
ORDER BY
cat_id;
//exists型
//把goods栏目下有商品的取出来
category表
+--------+----------+
| cat_id | cat_name |
+--------+----------+
| 1 | 手机类型 |
| 3 | 小型手机 |
| 4 | 3G手机 |
| 6 | 手机 |
| 8 | 耳机 |
| 9 | 电池 |
| 12 | 充值卡 |
| 16 | 服装 |
| 18 | 智能硬件 |
| 19 | 配件 |
| 20 | 保护壳 |
| 22 | 移动电源 |
| 24 | 数码时尚 |
+--------+----------+
goods表
+--------+----------+-------------------------------------+
| cat_id | goods_id | goods_name |
+--------+----------+-------------------------------------+
| 3 | 8 | 飞利浦9@9v |
| 4 | 1 | KD876 |
| 6 | 54 | 插线板 |
| 8 | 4 | 诺基亚N85原装充电器
| 16 | 42 | 短袖T恤 米兔大游行
| 18 | 36 | 路由器 |
| 19 | 35 | 体重秤 |
| 20 | 58 | 手机3高配版 超薄钢化玻璃膜(0.22mm)
| 22 | 55 | 移动电源10000mAh |
| 24 | 61 | 视频 |
+--------+----------+-------------------------------------+
mysql> select cat_id,cat_name from category
-> where exists (select * from goods where goods.cat_id=category.cat_id);
+--------+----------+
| cat_id | cat_name |
+--------+----------+
| 3 | 小型手机 |
| 4 | 3G手机 |
| 6 | 手机 |
| 8 | 耳机 |
| 16 | 服装 |
| 18 | 智能硬件 |
| 19 | 配件 |
| 20 | 保护壳 |
| 25 | 数码时尚 |
| 22 | 移动电源 |
| 24 | 数码时尚 |
+--------+----------+
11 rows in set (0.02 sec)
NULL
mysql> select * from test2;
+-------+
| sname |
+-------+
| 张三 |
| 李四 |
| NULL |
+-------+
3 rows in set (0.00 sec)
mysql> select * from test2 where sname is not null;
+-------+
| sname |
+-------+
| 张三 |
| 李四 |
+-------+
2 rows in set (0.02 sec)
mysql> select * from test2 where sname is null;
+-------+
| sname |
+-------+
| NULL |
+-------+
1 row in set (0.00 sec)
mysql> select * from test2 where sname=null;
Empty set (0.00 sec)
mysql> select * from test2 where sname!=null;
Empty set (0.00 sec)
mysql> select 2>1;
+-----+
| 2>1 |
+-----+
| 1 |
+-----+
1 row in set (0.00 sec)
mysql> select 1>2;
+-----+
| 1>2 |
+-----+
| 0 |
+-----+
1 row in set (0.00 sec)
mysql> select 2*3;
+-----+
| 2*3 |
+-----+
| 6 |
+-----+
1 row in set (0.00 sec)
mysql> select null=null;
+-----------+
| null=null |
+-----------+
| NULL |
+-----------+
1 row in set (0.00 sec)
mysql> select null!=null;
+------------+
| null!=null |
+------------+
| NULL |
+------------+