MySQL的开发技巧3

参考:

1、 MySQL开发技巧

2、 MySQL开发技巧2

3、MySQL开发技巧3

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

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

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

子查询使用的场景

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

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


   
   
  1. mysql > set names 'GBK';
  2. Query OK, 0 rows affected ( 0.00 sec)
  3. mysql > select user_name
  4. - > from user1
  5. - > where id in( select user_id from user_kills);
  6. + -----------+
  7. | user_name |
  8. + -----------+
  9. | 孙悟空 |
  10. | 沙僧 |
  11. | 猪八戒 |
  12. + -----------+
  13. 3 rows in set ( 0.01 sec)
  14. -- 子查询的表user_kills中有重复的数据。
  15. mysql > select * from user_kills;
  16. + ----+---------+---------------------+-------+
  17. | id | user_id | timestr | kills |
  18. + ----+---------+---------------------+-------+
  19. | 1 | 2 | 2013 -01 -10 00: 00: 00 | 10 |
  20. | 2 | 2 | 2013 -02 -01 00: 00: 00 | 2 |
  21. | 3 | 2 | 2013 -02 -05 00: 00: 00 | 12 |
  22. | 4 | 4 | 2013 -01 -10 00: 00: 00 | 3 |
  23. | 5 | 4 | 2013 -02 -11 00: 00: 00 | 5 |
  24. | 6 | 4 | 2013 -02 -06 00: 00: 00 | 1 |
  25. | 7 | 3 | 2013 -01 -11 00: 00: 00 | 20 |
  26. | 8 | 3 | 2013 -02 -12 00: 00: 00 | 10 |
  27. | 9 | 3 | 2013 -02 -07 00: 00: 00 | 17 |
  28. + ----+---------+---------------------+-------+
  29. 9 rows in set ( 0.00 sec)
  30. -- 如果使用连接,就会有重复数据
  31. mysql > select user_name
  32. - > from user1
  33. - > left join user_kills on user1.id = user_kills.user_id;
  34. + -----------+
  35. | user_name |
  36. + -----------+
  37. | 唐僧 |
  38. | 孙悟空 |
  39. | 孙悟空 |
  40. | 孙悟空 |
  41. | 沙僧 |
  42. | 沙僧 |
  43. | 沙僧 |
  44. | 猪八戒 |
  45. | 猪八戒 |
  46. | 猪八戒 |
  47. + -----------+
  48. 10 rows in set ( 0.00 sec)
  49. -- 如果使用连接,就会有重复数据--》解决方法:distinct
  50. mysql > select distinct user_name
  51. - > from user1
  52. - > left join user_kills on user1.id = user_kills.user_id;
  53. + -----------+
  54. | user_name |
  55. + -----------+
  56. | 唐僧 |
  57. | 孙悟空 |
  58. | 沙僧 |
  59. | 猪八戒 |
  60. + -----------+
  61. 4 rows in set ( 0.01 sec)
  • 使用子查询更符合语意,更好理解

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

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


   
   
  1. mysql > -- S1-取出user_id及最多的打怪数量
  2. mysql > select user_id, MAX(kills) as max_cnt
  3. - > from user_kills
  4. - > GROUP BY user_id;
  5. + ---------+---------+
  6. | user_id | max_cnt |
  7. + ---------+---------+
  8. | 2 | 12 |
  9. | 3 | 20 |
  10. | 4 | 5 |
  11. + ---------+---------+
  12. 3 rows in set ( 0.00 sec)
  13. mysql > -- S2-取经人的姓名、打怪最多的日期和打怪的数量
  14. mysql > select a.user_name,b.timestr,kills
  15. - > from user1 a
  16. - > join user_kills b on a.id = b.user_id
  17. - > join ( select user_id, max(kills) as max_cnt
  18. - > from user_kills
  19. - > group by user_id
  20. - > ) c on b.user_id = c.user_id and b.kills = c.max_cnt
  21. - > ;
  22. + -----------+---------------------+-------+
  23. | user_name | timestr | kills |
  24. + -----------+---------------------+-------+
  25. | 猪八戒 | 2013 -02 -05 00: 00: 00 | 12 |
  26. | 沙僧 | 2013 -02 -11 00: 00: 00 | 5 |
  27. | 孙悟空 | 2013 -01 -11 00: 00: 00 | 20 |
  28. + -----------+---------------------+-------+
  29. 3 rows in set ( 0.01 sec)
  30. mysql >

方法2:多列过滤。

MySQL中独有的多列过滤方式


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

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

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

添加一个技能表


   
   
  1. mysql > --
  2. mysql > -- Table structure for table `user1_skills`
  3. mysql > --
  4. mysql > CREATE TABLE user1_skills (
  5. - > id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  6. - > user_id INT UNSIGNED NOT NULL,
  7. - > skill VARCHAR( 10) NULL,
  8. - > skill_level INT UNSIGNED NOT NULL DEFAULT 0,
  9. - > PRIMARY KEY (id)
  10. - > )ENGINE =InnoDB DEFAULT CHARSET =utf8;
  11. Query OK, 0 rows affected ( 0.01 sec)
  12. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 1, '紧箍咒', 5);
  13. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 1, '打坐', 4);
  14. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 1, '念经', 5);
  15. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 1, '变化', 0);
  16. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 2, '变化', 4);
  17. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 2, '腾云', 3);
  18. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 2, '浮水', 5);
  19. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 2, '念经', 0);
  20. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 2, '紧箍咒', 0);
  21. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 3, '变化', 5);
  22. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 3, '腾云', 5);
  23. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 3, '浮水', 3);
  24. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 3, '念经', 2);
  25. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 3, '请神', 5);
  26. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 3, '紧箍咒', 0);
  27. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 3, '紧箍咒', 0);
  28. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 4, '变化', 2);
  29. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 4, '腾云', 2);
  30. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 4, '浮水', 4);
  31. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 4, '念经', 1);
  32. INSERT INTO user1_skills (user_id,skill,skill_level) VALUES( 4, '紧箍咒', 0);

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


   
   
  1. mysql > select a.user_name,b.skill,b.skill_level
  2. - > from user1 a
  3. - > join user1_skills b on a.id = b.user_id
  4. - > where skill in( '变化', '念经') and skill_level > 0;
  5. + -----------+-------+-------------+
  6. | user_name | skill | skill_level |
  7. + -----------+-------+-------------+
  8. | 唐僧 | 念经 | 5 |
  9. | 猪八戒 | 变化 | 4 |
  10. | 孙悟空 | 变化 | 5 |
  11. | 孙悟空 | 念经 | 2 |
  12. | 沙僧 | 变化 | 2 |
  13. | 沙僧 | 念经 | 1 |
  14. + -----------+-------+-------------+
  15. 6 rows in set ( 0.00 sec)
  16. -- 使用join
  17. mysql > select a.user_name,b.skill,c.skill
  18. - > from user1 a
  19. - > join user1_skills b on a.id = b.user_id and b.skill = '念经'
  20. - > join user1_skills c on b.user_id = c.user_id and c.skill = '变化'
  21. - > where b.skill_level > 0 and c.skill_level > 0;
  22. + -----------+-------+-------+
  23. | user_name | skill | skill |
  24. + -----------+-------+-------+
  25. | 孙悟空 | 念经 | 变化 |
  26. | 沙僧 | 念经 | 变化 |
  27. + -----------+-------+-------+
  28. 2 rows in set ( 0.00 sec)
  29. mysql > -- 如何查询出同时具有变化和念经、腾云,这3项技能的取经人?
  30. mysql > -- 使用join
  31. mysql > select a.user_name,b.skill,c.skill,d.skill
  32. - > from user1 a
  33. - > join user1_skills b on a.id = b.user_id and b.skill = '念经'
  34. - > join user1_skills c on b.user_id = c.user_id and c.skill = '变化'
  35. - > join user1_skills d on c.user_id = d.user_id and d.skill = '腾云'
  36. - > where b.skill_level > 0 and c.skill_level > 0 and d.skill_level > 0;
  37. + -----------+-------+-------+-------+
  38. | user_name | skill | skill | skill |
  39. + -----------+-------+-------+-------+
  40. | 孙悟空 | 念经 | 变化 | 腾云 |
  41. | 沙僧 | 念经 | 变化 | 腾云 |
  42. + -----------+-------+-------+-------+
  43. 2 rows in set ( 0.00 sec)

改进,使用LEFT JOIN代替 JOIN


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

 是拥有两种及以上技能?


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

使用GROUP方法解决问题


   
   
  1. mysql > -- 使用GROUP方法解决问题
  2. mysql > select a.user_name
  3. - > from user1 a
  4. - > join user1_skills b on a.id = b.user_id
  5. - > where b.skill in( '念经', '变化', '腾云', '浮水') and b.skill_level > 0
  6. - > GROUP By a.user_name
  7. - > HAVING count( *) >= 2
  8. - > ;
  9. + -----------+
  10. | user_name |
  11. + -----------+
  12. | 孙悟空 |
  13. | 沙僧 |
  14. | 猪八戒 |
  15. + -----------+
  16. 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


   
   
  1. mysql > ALTER TABLE user1 ADD money float NULL;
  2. Query OK, 4 rows affected ( 0.03 sec)
  3. Records: 4 Duplicates: 0 Warnings: 0
  4. mysql > desc user1;
  5. + -----------+------------------+------+-----+---------+----------------+
  6. | Field | Type | Null | Key | Default | Extra |
  7. + -----------+------------------+------+-----+---------+----------------+
  8. | id | int( 10) unsigned | NO | PRI | NULL | auto_increment |
  9. | user_name | varchar( 30) | NO | MUL | NULL | |
  10. | over | varchar( 50) | YES | | NULL | |
  11. | mobile | varchar( 100) | YES | | NULL | |
  12. | money | float | YES | | NULL | |
  13. + -----------+------------------+------+-----+---------+----------------+
  14. 5 rows in set ( 0.01 sec)
  15. -- 更新 user1表的money字段
  16. update user1 set money = 35000 where id = 1;
  17. update user1 set money = 15000 where id = 2;
  18. update user1 set money = 28000 where id = 3;
  19. update user1 set money = 8000 where id = 4;
  20. --
  21. -- Table structure for table `taxRate`
  22. --
  23. CREATE TABLE taxRate (
  24. id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  25. low float NOT NULL,
  26. high float NOT NULL,
  27. rate float NOT NULL,
  28. tax_money float NULL,
  29. PRIMARY KEY (id)
  30. )ENGINE =InnoDB DEFAULT CHARSET =utf8;
  31. -- 插入 taxRate
  32. insert taxRate (low,high,rate) VALUES( 0, 1500, 0.03);
  33. insert taxRate (low,high,rate) VALUES( 1500, 4500, 0.10);
  34. insert taxRate (low,high,rate) VALUES( 4500, 9000, 0.20);
  35. insert taxRate (low,high,rate) VALUES( 9000, 35000, 0.25);
  36. insert taxRate (low,high,rate) VALUES( 35000, 55000, 0.30);
  37. insert taxRate (low,high,rate) VALUES( 55000, 80000, 0.35);
  38. insert taxRate (low,high,rate) VALUES( 80000, 999999999.00, 0.45);
  39. mysql > select user_name,money from user1;
  40. + -----------+-------+
  41. | user_name | money |
  42. + -----------+-------+
  43. | 唐僧 | 35000 |
  44. | 猪八戒 | 15000 |
  45. | 孙悟空 | 28000 |
  46. | 沙僧 | 8000 |
  47. + -----------+-------+
  48. 4 rows in set ( 0.00 sec)
  49. mysql > select * from taxRate;
  50. + ----+-------+------------+------+-----------+
  51. | id | low | high | rate | tax_money |
  52. + ----+-------+------------+------+-----------+
  53. | 1 | 0 | 1500 | 0.03 | NULL |
  54. | 2 | 1500 | 4500 | 0.1 | NULL |
  55. | 3 | 4500 | 9000 | 0.2 | NULL |
  56. | 4 | 9000 | 35000 | 0.25 | NULL |
  57. | 5 | 35000 | 55000 | 0.3 | NULL |
  58. | 6 | 55000 | 80000 | 0.35 | NULL |
  59. | 7 | 80000 | 1000000000 | 0.45 | NULL |
  60. + ----+-------+------------+------+-----------+
  61. 7 rows in set ( 0.00 sec)

 

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


   
   
  1. mysql > -- 查询税类
  2. mysql > select a.user_name,money,low,high,rate
  3. - > from user1 a
  4. - > join taxRate b on a.money > b.low
  5. - > order by a.user_name,b.id
  6. - >
  7. - > ;
  8. + -----------+-------+------+-------+------+
  9. | user_name | money | low | high | rate |
  10. + -----------+-------+------+-------+------+
  11. | 唐僧 | 35000 | 0 | 1500 | 0.03 |
  12. | 唐僧 | 35000 | 1500 | 4500 | 0.1 |
  13. | 唐僧 | 35000 | 4500 | 9000 | 0.2 |
  14. | 唐僧 | 35000 | 9000 | 35000 | 0.25 |
  15. | 孙悟空 | 28000 | 0 | 1500 | 0.03 |
  16. | 孙悟空 | 28000 | 1500 | 4500 | 0.1 |
  17. | 孙悟空 | 28000 | 4500 | 9000 | 0.2 |
  18. | 孙悟空 | 28000 | 9000 | 35000 | 0.25 |
  19. | 沙僧 | 8000 | 0 | 1500 | 0.03 |
  20. | 沙僧 | 8000 | 1500 | 4500 | 0.1 |
  21. | 沙僧 | 8000 | 4500 | 9000 | 0.2 |
  22. | 猪八戒 | 15000 | 0 | 1500 | 0.03 |
  23. | 猪八戒 | 15000 | 1500 | 4500 | 0.1 |
  24. | 猪八戒 | 15000 | 4500 | 9000 | 0.2 |
  25. | 猪八戒 | 15000 | 9000 | 35000 | 0.25 |
  26. + -----------+-------+------+-------+------+
  27. 15 rows in set ( 0.00 sec)

 


   
   
  1. mysql > -- 查询税类区间
  2. mysql > select a.user_name,money,low,high,least(money -low,high -low) as curmoney,rate
  3. - > from user1 a
  4. - > join taxRate b on a.money > b.low
  5. - > order by a.user_name,b.id
  6. - > ;
  7. + -----------+-------+------+-------+----------+------+
  8. | user_name | money | low | high | curmoney | rate |
  9. + -----------+-------+------+-------+----------+------+
  10. | 唐僧 | 35000 | 0 | 1500 | 1500 | 0.03 |
  11. | 唐僧 | 35000 | 1500 | 4500 | 3000 | 0.1 |
  12. | 唐僧 | 35000 | 4500 | 9000 | 4500 | 0.2 |
  13. | 唐僧 | 35000 | 9000 | 35000 | 26000 | 0.25 |
  14. | 孙悟空 | 28000 | 0 | 1500 | 1500 | 0.03 |
  15. | 孙悟空 | 28000 | 1500 | 4500 | 3000 | 0.1 |
  16. | 孙悟空 | 28000 | 4500 | 9000 | 4500 | 0.2 |
  17. | 孙悟空 | 28000 | 9000 | 35000 | 19000 | 0.25 |
  18. | 沙僧 | 8000 | 0 | 1500 | 1500 | 0.03 |
  19. | 沙僧 | 8000 | 1500 | 4500 | 3000 | 0.1 |
  20. | 沙僧 | 8000 | 4500 | 9000 | 3500 | 0.2 |
  21. | 猪八戒 | 15000 | 0 | 1500 | 1500 | 0.03 |
  22. | 猪八戒 | 15000 | 1500 | 4500 | 3000 | 0.1 |
  23. | 猪八戒 | 15000 | 4500 | 9000 | 4500 | 0.2 |
  24. | 猪八戒 | 15000 | 9000 | 35000 | 6000 | 0.25 |
  25. + -----------+-------+------+-------+----------+------+
  26. 15 rows in set ( 0.00 sec)
  27. mysql > -- 查询每人税类总额
  28. mysql > select user_name, sum(curmoney *rate)
  29. - > from(
  30. - > select a.user_name,money,low,high,least(money -low,high -low) as curmoney,rate
  31. - > from user1 a
  32. - > join taxRate b on a.money > b.low
  33. - > ) a
  34. - > GROUP BY user_name
  35. - > ;
  36. + -----------+--------------------+
  37. | user_name | sum(curmoney *rate) |
  38. + -----------+--------------------+
  39. | 唐僧 | 7745.000016875565 |
  40. | 孙悟空 | 5995.000016875565 |
  41. | 沙僧 | 1045.0000138953328 |
  42. | 猪八戒 | 2745.000016875565 |
  43. + -----------+--------------------+
  44. 4 rows in set ( 0.00 sec)

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值