MySQL的开发技巧3

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34515002/article/details/81567186

参考:

1、 MySQL开发技巧

2、 MySQL开发技巧2

3、MySQL开发技巧3

1、如何在子查询中测试两个值

2、如何解决多属性查询问题

3、如何计算累进税类问题

子查询使用的场景

  • 使用子查询可以避免由于子查询中数据产生的重复

例子:有哪些人在取经过程中打了怪

mysql> set names 'GBK';
Query OK, 0 rows affected (0.00 sec)

mysql> select user_name
    -> from user1
    -> where id in(select user_id from user_kills);
+-----------+
| user_name |
+-----------+
| 孙悟空          |
| 沙僧        |
| 猪八戒         |
+-----------+
3 rows in set (0.01 sec)

-- 子查询的表user_kills中有重复的数据。
mysql> select * from user_kills;
+----+---------+---------------------+-------+
| id | user_id | timestr             | kills |
+----+---------+---------------------+-------+
|  1 |       2 | 2013-01-10 00:00:00 |    10 |
|  2 |       2 | 2013-02-01 00:00:00 |     2 |
|  3 |       2 | 2013-02-05 00:00:00 |    12 |
|  4 |       4 | 2013-01-10 00:00:00 |     3 |
|  5 |       4 | 2013-02-11 00:00:00 |     5 |
|  6 |       4 | 2013-02-06 00:00:00 |     1 |
|  7 |       3 | 2013-01-11 00:00:00 |    20 |
|  8 |       3 | 2013-02-12 00:00:00 |    10 |
|  9 |       3 | 2013-02-07 00:00:00 |    17 |
+----+---------+---------------------+-------+
9 rows in set (0.00 sec)

-- 如果使用连接,就会有重复数据

mysql> select user_name
    -> from user1
    -> left join user_kills on user1.id = user_kills.user_id;
+-----------+
| user_name |
+-----------+
| 唐僧         |
| 孙悟空          |
| 孙悟空          |
| 孙悟空          |
| 沙僧        |
| 沙僧        |
| 沙僧        |
| 猪八戒         |
| 猪八戒         |
| 猪八戒         |
+-----------+
10 rows in set (0.00 sec)

-- 如果使用连接,就会有重复数据--》解决方法:distinct


mysql> select distinct user_name
    -> from user1
    -> left join user_kills on user1.id = user_kills.user_id;
+-----------+
| user_name |
+-----------+
| 唐僧         |
| 孙悟空          |
| 沙僧        |
| 猪八戒         |
+-----------+
4 rows in set (0.01 sec)


  • 使用子查询更符合语意,更好理解

如何在子查询中匹配两个值

查询出每一个取经人打怪最多的日期,并列出取经人的姓名、打怪最多的日期和打怪的数量。

mysql> -- S1-取出user_id及最多的打怪数量
mysql> select user_id,MAX(kills) as max_cnt
    -> from user_kills
    -> GROUP BY user_id;
+---------+---------+
| user_id | max_cnt |
+---------+---------+
|       2 |      12 |
|       3 |      20 |
|       4 |       5 |
+---------+---------+
3 rows in set (0.00 sec)

mysql> -- S2-取经人的姓名、打怪最多的日期和打怪的数量
mysql> select a.user_name,b.timestr,kills
    -> from user1 a
    -> join user_kills b on a.id = b.user_id
    -> join ( select user_id,max(kills) as max_cnt
    ->         from user_kills
    ->         group by user_id
    -> ) c on b.user_id = c.user_id and b.kills = c.max_cnt
    -> ;
+-----------+---------------------+-------+
| user_name | timestr             | kills |
+-----------+---------------------+-------+
| 猪八戒         | 2013-02-05 00:00:00 |    12 |
| 沙僧        | 2013-02-11 00:00:00 |     5 |
| 孙悟空          | 2013-01-11 00:00:00 |    20 |
+-----------+---------------------+-------+
3 rows in set (0.01 sec)

mysql>

方法2:多列过滤。

MySQL中独有的多列过滤方式

mysql> -- 查询出每一个取经人打怪最多的日期,并列出取经人的姓名、打怪最多的日期和打怪的数量。
mysql> -- 多列过滤
mysql> SELECT a.user_name,b.timestr,kills
    -> from user1 a
    -> join user_kills b on a.id=b.user_id
    -> WHERE (b.user_id,b.kills) IN (
    ->       SELECT user_id,max(kills)
    ->       FROM user_kills
    ->       GROUP BY user_id
    -> );
+-----------+---------------------+-------+
| user_name | timestr             | kills |
+-----------+---------------------+-------+
| 猪八戒         | 2013-02-05 00:00:00 |    12 |
| 沙僧        | 2013-02-11 00:00:00 |     5 |
| 孙悟空          | 2013-01-11 00:00:00 |    20 |
+-----------+---------------------+-------+
3 rows in set (0.00 sec)

如何解决同一属性的多值过滤

什么是同一属性的多值过滤

添加一个技能表

mysql> --
mysql> -- Table structure for table `user1_skills`
mysql> --
mysql> CREATE TABLE user1_skills (
    ->   id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    ->   user_id  INT UNSIGNED NOT  NULL,
    ->   skill VARCHAR(10) NULL,
    ->   skill_level INT UNSIGNED NOT NULL DEFAULT 0,
    ->   PRIMARY KEY  (id)
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.01 sec)

INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(1,'紧箍咒',5);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(1,'打坐',4);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(1,'念经',5);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(1,'变化',0);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(2,'变化',4);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(2,'腾云',3);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(2,'浮水',5);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(2,'念经',0);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(2,'紧箍咒',0);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(3,'变化',5);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(3,'腾云',5);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(3,'浮水',3);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(3,'念经',2);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(3,'请神',5);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(3,'紧箍咒',0);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(3,'紧箍咒',0);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(4,'变化',2);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(4,'腾云',2);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(4,'浮水',4);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(4,'念经',1);
INSERT INTO user1_skills (user_id,skill,skill_level) VALUES(4,'紧箍咒',0);

如何查询出同时具有变化和念经这两项技能的取经人?



mysql> select a.user_name,b.skill,b.skill_level
    -> from user1 a
    -> join user1_skills b on a.id = b.user_id
    -> where skill in('变化','念经') and skill_level >0;
+-----------+-------+-------------+
| user_name | skill | skill_level |
+-----------+-------+-------------+
| 唐僧         | 念经     |           5 |
| 猪八戒         | 变化    |           4 |
| 孙悟空          | 变化    |           5 |
| 孙悟空          | 念经     |           2 |
| 沙僧        | 变化    |           2 |
| 沙僧        | 念经     |           1 |
+-----------+-------+-------------+
6 rows in set (0.00 sec)

-- 使用join

mysql> select a.user_name,b.skill,c.skill
    -> from user1 a
    -> join user1_skills b on a.id = b.user_id and b.skill='念经'
    -> join user1_skills c on b.user_id = c.user_id and c.skill='变化'
    -> where b.skill_level >0 and c.skill_level >0;
+-----------+-------+-------+
| user_name | skill | skill |
+-----------+-------+-------+
| 孙悟空          | 念经     | 变化    |
| 沙僧        | 念经     | 变化    |
+-----------+-------+-------+
2 rows in set (0.00 sec)


mysql> -- 如何查询出同时具有变化和念经、腾云,这3项技能的取经人?
mysql> -- 使用join
mysql> select a.user_name,b.skill,c.skill,d.skill
    -> from user1 a
    -> join user1_skills b on a.id = b.user_id and b.skill='念经'
    -> join user1_skills c on b.user_id = c.user_id and c.skill='变化'
    -> join user1_skills d on c.user_id = d.user_id and d.skill='腾云'
    -> where b.skill_level >0 and c.skill_level >0 and d.skill_level>0;
+-----------+-------+-------+-------+
| user_name | skill | skill | skill |
+-----------+-------+-------+-------+
| 孙悟空          | 念经     | 变化    | 腾云      |
| 沙僧        | 念经     | 变化    | 腾云      |
+-----------+-------+-------+-------+
2 rows in set (0.00 sec)

改进,使用LEFT JOIN代替 JOIN

mysql> -- 如何查询出同时具有变化和念经、腾云,这3项技能的取经人?
mysql> -- 改进:使用left join
mysql> select a.user_name,b.skill,c.skill,d.skill,e.skill
    -> from user1 a
    -> left join user1_skills b on a.id = b.user_id and b.skill='念经' and b.skill_level >0
    -> left join user1_skills c on a.id = c.user_id and c.skill='变化' and c.skill_level >0
    -> left join user1_skills d on a.id = d.user_id and d.skill='腾云' and d.skill_level >0
    -> left join user1_skills e on a.id = e.user_id and e.skill='浮水' and e.skill_level >0
    -> ;
+-----------+-------+-------+-------+-------+
| user_name | skill | skill | skill | skill |
+-----------+-------+-------+-------+-------+
| 唐僧         | 念经     | NULL  | NULL  | NULL  |
| 孙悟空          | 念经     | 变化    | 腾云      | 浮水     |
| 沙僧        | 念经     | 变化    | 腾云      | 浮水     |
| 猪八戒         | NULL  | 变化    | 腾云      | 浮水     |
+-----------+-------+-------+-------+-------+
4 rows in set (0.00 sec)

 是拥有两种及以上技能?

mysql> --  是拥有两种及以上技能?
mysql> select a.user_name,b.skill,c.skill,d.skill,e.skill
    -> from user1 a
    -> left join user1_skills b on a.id = b.user_id and b.skill='念经' and b.skill_level >0
    -> left join user1_skills c on a.id = c.user_id and c.skill='变化' and c.skill_level >0
    -> left join user1_skills d on a.id = d.user_id and d.skill='腾云' and d.skill_level >0
    -> left join user1_skills e on a.id = e.user_id and e.skill='浮水' and e.skill_level >0
    -> where (case when b.skill is not null then 1 else 0 end)
    -> + (case when c.skill is not null then 1 else 0 end)
    -> + (case when d.skill is not null then 1 else 0 end)
    -> + (case when e.skill is not null then 1 else 0 end)>=2
    -> ;
+-----------+-------+-------+-------+-------+
| user_name | skill | skill | skill | skill |
+-----------+-------+-------+-------+-------+
| 孙悟空          | 念经     | 变化    | 腾云      | 浮水     |
| 沙僧        | 念经     | 变化    | 腾云      | 浮水     |
| 猪八戒         | NULL  | 变化    | 腾云      | 浮水     |
+-----------+-------+-------+-------+-------+
3 rows in set (0.00 sec)

使用GROUP方法解决问题

mysql> -- 使用GROUP方法解决问题
mysql> select a.user_name
    -> from user1 a
    -> join user1_skills b on a.id = b.user_id
    -> where b.skill in('念经','变化','腾云','浮水') and b.skill_level >0
    -> GROUP By a.user_name
    -> HAVING count(*) >=2
    -> ;
+-----------+
| user_name |
+-----------+
| 孙悟空          |
| 沙僧        |
| 猪八戒         |
+-----------+
3 rows in set (0.00 sec)

如何计算累进税类问题

什么是累进税?——最常见:个人所得税

全月应纳税所得额

税率

速算扣除数(元)

全月应纳税所得额不超过1500元

3%

0

全月应纳税所得额超过1500元至4500元

10%

105

全月应纳税所得额超过4500元至9000元

20%

555

全月应纳税所得额超过9000元至35000元

25%

1005

全月应纳税所得额超过35000元至55000元

30%

2755

全月应纳税所得额超过55000元至80000元

35%

5505

全月应纳税所得额超过80000元

45%

13505

mysql> ALTER TABLE user1 ADD money float   NULL;
Query OK, 4 rows affected (0.03 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> desc user1;
+-----------+------------------+------+-----+---------+----------------+
| Field     | Type             | Null | Key | Default | Extra          |
+-----------+------------------+------+-----+---------+----------------+
| id        | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| user_name | varchar(30)      | NO   | MUL | NULL    |                |
| over      | varchar(50)      | YES  |     | NULL    |                |
| mobile    | varchar(100)     | YES  |     | NULL    |                |
| money     | float            | YES  |     | NULL    |                |
+-----------+------------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)

-- 更新 user1表的money字段
update user1 set money = 35000 where id =1;
update user1 set money = 15000 where id =2;
update user1 set money = 28000 where id =3;
update user1 set money = 8000 where id =4;

--
-- Table structure for table `taxRate`
--
CREATE TABLE taxRate (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  low float NOT  NULL,
  high float NOT NULL,
  rate float NOT NULL,
  tax_money float NULL,
  PRIMARY KEY  (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- 插入 taxRate
insert taxRate (low,high,rate) VALUES(0,1500,0.03);
insert taxRate (low,high,rate) VALUES(1500,4500,0.10);
insert taxRate (low,high,rate) VALUES(4500,9000,0.20);
insert taxRate (low,high,rate) VALUES(9000,35000,0.25);
insert taxRate (low,high,rate) VALUES(35000,55000,0.30);
insert taxRate (low,high,rate) VALUES(55000,80000,0.35);
insert taxRate (low,high,rate) VALUES(80000,999999999.00,0.45);



mysql> select user_name,money from user1;
+-----------+-------+
| user_name | money |
+-----------+-------+
| 唐僧         | 35000 |
| 猪八戒         | 15000 |
| 孙悟空          | 28000 |
| 沙僧        |  8000 |
+-----------+-------+
4 rows in set (0.00 sec)

mysql> select * from taxRate;
+----+-------+------------+------+-----------+
| id | low   | high       | rate | tax_money |
+----+-------+------------+------+-----------+
|  1 |     0 |       1500 | 0.03 |      NULL |
|  2 |  1500 |       4500 |  0.1 |      NULL |
|  3 |  4500 |       9000 |  0.2 |      NULL |
|  4 |  9000 |      35000 | 0.25 |      NULL |
|  5 | 35000 |      55000 |  0.3 |      NULL |
|  6 | 55000 |      80000 | 0.35 |      NULL |
|  7 | 80000 | 1000000000 | 0.45 |      NULL |
+----+-------+------------+------+-----------+
7 rows in set (0.00 sec)

使用JON实现工资对不同纳税区间的匹配

mysql> -- 查询税类
mysql> select a.user_name,money,low,high,rate
    -> from user1 a
    -> join taxRate b on a.money > b.low
    -> order by a.user_name,b.id
    ->
    -> ;
+-----------+-------+------+-------+------+
| user_name | money | low  | high  | rate |
+-----------+-------+------+-------+------+
| 唐僧         | 35000 |    0 |  1500 | 0.03 |
| 唐僧         | 35000 | 1500 |  4500 |  0.1 |
| 唐僧         | 35000 | 4500 |  9000 |  0.2 |
| 唐僧         | 35000 | 9000 | 35000 | 0.25 |
| 孙悟空          | 28000 |    0 |  1500 | 0.03 |
| 孙悟空          | 28000 | 1500 |  4500 |  0.1 |
| 孙悟空          | 28000 | 4500 |  9000 |  0.2 |
| 孙悟空          | 28000 | 9000 | 35000 | 0.25 |
| 沙僧        |  8000 |    0 |  1500 | 0.03 |
| 沙僧        |  8000 | 1500 |  4500 |  0.1 |
| 沙僧        |  8000 | 4500 |  9000 |  0.2 |
| 猪八戒         | 15000 |    0 |  1500 | 0.03 |
| 猪八戒         | 15000 | 1500 |  4500 |  0.1 |
| 猪八戒         | 15000 | 4500 |  9000 |  0.2 |
| 猪八戒         | 15000 | 9000 | 35000 | 0.25 |
+-----------+-------+------+-------+------+
15 rows in set (0.00 sec)

mysql> -- 查询税类区间
mysql> select a.user_name,money,low,high,least(money-low,high-low) as curmoney,rate
    -> from user1 a
    -> join taxRate b on a.money > b.low
    -> order by a.user_name,b.id
    -> ;
+-----------+-------+------+-------+----------+------+
| user_name | money | low  | high  | curmoney | rate |
+-----------+-------+------+-------+----------+------+
| 唐僧         | 35000 |    0 |  1500 |     1500 | 0.03 |
| 唐僧         | 35000 | 1500 |  4500 |     3000 |  0.1 |
| 唐僧         | 35000 | 4500 |  9000 |     4500 |  0.2 |
| 唐僧         | 35000 | 9000 | 35000 |    26000 | 0.25 |
| 孙悟空          | 28000 |    0 |  1500 |     1500 | 0.03 |
| 孙悟空          | 28000 | 1500 |  4500 |     3000 |  0.1 |
| 孙悟空          | 28000 | 4500 |  9000 |     4500 |  0.2 |
| 孙悟空          | 28000 | 9000 | 35000 |    19000 | 0.25 |
| 沙僧        |  8000 |    0 |  1500 |     1500 | 0.03 |
| 沙僧        |  8000 | 1500 |  4500 |     3000 |  0.1 |
| 沙僧        |  8000 | 4500 |  9000 |     3500 |  0.2 |
| 猪八戒         | 15000 |    0 |  1500 |     1500 | 0.03 |
| 猪八戒         | 15000 | 1500 |  4500 |     3000 |  0.1 |
| 猪八戒         | 15000 | 4500 |  9000 |     4500 |  0.2 |
| 猪八戒         | 15000 | 9000 | 35000 |     6000 | 0.25 |
+-----------+-------+------+-------+----------+------+
15 rows in set (0.00 sec)


mysql> -- 查询每人税类总额
mysql> select user_name,sum(curmoney*rate)
    -> from(
    ->   select a.user_name,money,low,high,least(money-low,high-low) as curmoney,rate
    ->   from user1 a
    ->   join taxRate b on a.money > b.low
    -> ) a
    -> GROUP BY user_name
    -> ;
+-----------+--------------------+
| user_name | sum(curmoney*rate) |
+-----------+--------------------+
| 唐僧         |  7745.000016875565 |
| 孙悟空          |  5995.000016875565 |
| 沙僧        | 1045.0000138953328 |
| 猪八戒         |  2745.000016875565 |
+-----------+--------------------+
4 rows in set (0.00 sec)

猜你喜欢

转载自blog.csdn.net/qq_34515002/article/details/81567186