group by,sum(),having count(*),case when探究

case when学习:
mysql> create table employee(name varchar(20),birthday int);
Query OK, 0 rows affected (0.02 sec)

mysql> insert into employee values ('liys',1989);
Query OK, 1 row affected (0.01 sec)

mysql> insert into employee values ('zhangs',1956);
Query OK, 1 row affected (0.00 sec)

mysql> insert into employee values ('wangs',1999);
Query OK, 1 row affected (0.00 sec)


mysql> select name,birthday,
    ->  case
    ->         when birthday<'1981' then 'old'
    ->         when birthday>'1990' then 'yong'
    ->         else 'ok' END YORN
    -> from employee;
+--------+----------+------+
| name   | birthday | YORN |
+--------+----------+------+
| liys   |     1989 | ok   |
| zhangs |     1956 | old  |
| wangs  |     1999 | yong |
+--------+----------+------+
3 rows in set (0.00 sec)
 

group by,sum(),having count(*)学习:
mysql> select * from employee;
+--------+----------+----------+
| name   | province | birthday |
+--------+----------+----------+
| liys   | beijing  | 1989     |
| liss   | beijing  | 1999     |
| zhnags | beijing  | 2000     |
| zss    | hebei    | 1978     |
| zssss  | hebei    | 1990     |
| zsaf   | hebei    | 2000     |
| zsaf   | sichuan  | 1945     |
| wag    | sichuan  | 1999     |
+--------+----------+----------+
8 rows in set (0.00 sec)

mysql> select province,sum(birthday) from employee group by province;
+----------+---------------+
| province | sum(birthday) |
+----------+---------------+
| beijing  |          5988 |
| hebei    |          5968 |
| sichuan  |          3944 |
+----------+---------------+
3 rows in set (0.00 sec)

mysql> select province,count(*) from employee group by province;
+----------+----------+
| province | count(*) |
+----------+----------+
| beijing  |        3 |
| hebei    |        3 |
| sichuan  |        2 |
+----------+----------+
3 rows in set (0.00 sec)


mysql> select province,count(*) from employee group by province having count(*)=2;
+----------+----------+
| province | count(*) |
+----------+----------+
| sichuan  |        2 |
+----------+----------+
1 row in set (0.01 sec)

mysql> select province,sum( case when birthday > 1999 then 1 else 0 end) from employee group by province;
+----------+---------------------------------------------------+
| province | sum( case when birthday > 1999 then 1 else 0 end) |
+----------+---------------------------------------------------+
| beijing  |                                                 1 |
| hebei    |                                                 1 |
| sichuan  |                                                 0 |
+----------+---------------------------------------------------+
3 rows in set (0.00 sec)


下面这个sql having count(*)= sum 实际是把count(*)中的所有数据又都过滤了一遍,组里面所有数据满足条件才会显出分组
mysql> select province,count(*) from employee group by province having count(*)= sum( case when birthday > 1960 then 1 else 0 end);
+----------+----------+
| province | count(*) |
+----------+----------+
| beijing  |        3 |
| hebei    |        3 |
+----------+----------+
2 rows in set (0.00 sec)

这种情况下往往需要把having count(*)= sum()里的过滤条件写到where里,因为having count(*)= sum()里面的sql不会走索引
mysql> select province,count(*) from employee where birthday > 1960 group by province;
+----------+----------+
| province | count(*) |
+----------+----------+
| beijing  |        3 |
| hebei    |        3 |
| sichuan  |        1 |
+----------+----------+
3 rows in set (0.00 sec)


那如何优化这个sql呢?
注意事项:having里面的逻辑是:分组后,同一组里面的每条记录都需要满足case when子句里面的条件,否则就丢弃。sql改写是要注意满足这个逻辑,否则会出现改写后的数据比原始sql执行的结果集要多


那就要用到exits这个功能了。
SQL中的(NOT) EXISTS是一种条件运算符,用于检查一个子查询是否返回结果,就是把where的结果集再筛选一遍,exist存在的就是说这一行的某个列值在另一个表里存在。
反之 not exits就是不存在另一个表里,把不存在的保留下来。

EXISTS:如果子查询返回至少一行结果,则返回true。它可以与WHERE子句一起使用,以根据子查询的结果过滤数据。
NOT EXISTS:如果子查询不返回任何结果,则返回true。它可以与WHERE子句一起使用,以排除具有特定条件的数据。
这两个运算符可以与SELECT、DELETE、UPDATE语句一起使用,以根据子查询返回的结果来决定要执行的操作。

mysql> select * from employee_b;
+------+
| name |
+------+
| liys |
| liss |
+------+
2 rows in set (0.00 sec)

mysql> select * from employee;
+--------+----------+----------+
| name   | province | birthday |
+--------+----------+----------+
| liys   | beijing  | 1989     |
| liss   | beijing  | 1999     |
| zhnags | beijing  | 2000     |
| zss    | hebei    | 1978     |
| zssss  | hebei    | 1990     |
| zsaf   | hebei    | 2000     |
| zsaf   | sichuan  | 1945     |
| wag    | sichuan  | 1999     |
+--------+----------+----------+
8 rows in set (0.00 sec)

mysql> select * from employee where province='beijing';
+--------+----------+----------+
| name   | province | birthday |
+--------+----------+----------+
| liys   | beijing  | 1989     |
| liss   | beijing  | 1999     |
| zhnags | beijing  | 2000     |
+--------+----------+----------+
3 rows in set (0.00 sec)


mysql> select * from employee where province='beijing' and  exists (select 1 from employee_b where employee_b.name=employee.name);
+------+----------+----------+
| name | province | birthday |
+------+----------+----------+
| liys | beijing  | 1989     |
| liss | beijing  | 1999     |
+------+----------+----------+
2 rows in set (0.00 sec)

mysql> select * from employee where province='beijing' and  not exists (select 1 from employee_b where employee_b.name=employee.name);
+--------+----------+----------+
| name   | province | birthday |
+--------+----------+----------+
| zhnags | beijing  | 2000     |
+--------+----------+----------+
1 row in set (0.00 sec)

mysql> select * from employee where  not ( birthday > 1960);
+------+----------+----------+
| name | province | birthday |
+------+----------+----------+
| zsaf | sichuan  | 1945     |
+------+----------+----------+
1 row in set (0.00 sec)


通过下面这个sql,就把province=sichuan的都过滤掉了

mysql> select * from employee a where birthday >1960 and not exists (select 1 from employee b where a.province=b.province and not (b.birthday > 1960));
+--------+----------+----------+
| name   | province | birthday |
+--------+----------+----------+
| liys   | beijing  | 1989     |
| liss   | beijing  | 1999     |
| zhnags | beijing  | 2000     |
| zss    | hebei    | 1978     |
| zssss  | hebei    | 1990     |
| zsaf   | hebei    | 2000     |
+--------+----------+----------+
6 rows in set (0.00 sec)

mysql>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值