MySQL的開發技巧3
阿新 • • 發佈:2018-11-08
參考:
1、 MySQL開發技巧
2、 MySQL開發技巧2
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)