一、前言
比如有兩個數據表,表結構是一樣的,一個a
表數據300W
行,一個b
表數據17W
行,我們需要獲取a
表中不包含b
表的數據。下面大致記錄一下獲取過程,方便查詢回憶。
a表結構:
id
pay_id
user_id
b
表結構和a
表一直,只不過b
表中的user_id
字段都是唯一的,而a
表中的user_id
字段是可重複的。
二、使用distinct獲取不重複的數據
我們都知道Mysql
提供了關鍵字distinct來排除重複數據,
1、先獲取a表中不重複的數據:
select count(distinct user_id) from a where 1 ;
+-----------------------------+
| count(distinct user_id) |
+-----------------------------+
| 240522 |
+-----------------------------+
2、獲取b表數據
mysql> select count(1) from b;
+----------+
| count(1) |
+----------+
| 176731 |
我們看到a
表和b
表是有一定的差值的,接下來是獲取差值對應的字段。
3、查詢篩選後的數據
SELECT distinct user_id FROM a LEFT JOIN b ON a.user_id= b.user_id WHERE f.user_id IS NULL ';
+-------------+
| user_id |
+-------------+
| 10000058 |
| 10009228 |
| 10042967 |
....
+-------------+
通過查詢結果,我們獲取到了不重複的user_id
的值,但是需求是獲取不重複的行數據,所以還要獲得a
表中pay_id
的值。只是在通過distinct
獲取其他數據的時候,遇到了一些 問題
4、distinct多個字段的問題
(1)不能是分散的寫法
如:distinct user_id,distinct user_id
這種寫法會報錯
(2)正確的distinct寫法
distinct user_id, pay_id
SELECT distinct p.user_id,p.pay_id FROM a as p LEFT JOIN b as f ON p.user_id = f.user_id
WHERE f.user_id IS NULL order by p.user_id asc limit 10;
類似於:
| user_id | pay_id |
+-------------+--------+
| 10000058 | 16 |
| 10000058 | 17 |
| 10000058 | 18 |
| 10000058 | 19 |
| 10000058 | 20 |
有個問題,distinct
多個字段,那麼只會排除user_id
和 pay_id
都相同的數據,並不符合需求,需求是隻排除user_id
重複的部分,然後獲取唯一user_id
以及對應的pay_id
(3)符合需求的寫法(使用left join)
SELECT a.pay_id,a.user_id FROM a LEFT JOIN b as f ON a.user_id = f.user_id
where f.user_id IS NULL GROUP BY a.user_id order by a.user_id desc limit 10;
+----------+-------------+
| pay_id | |user_id |
+----------+-------------+
| 16 | 10000058 |
| 15 | 10009228 |
| 77 | 10042967 |
| 687 | 10043113 |
| 119 | 10043147 |
我們這裏沒有使用distinct
關鍵字,首先是使用left join
去除兩個表中重複的部分,其次是使用group by
的去重特性,當按照user_id
分組的時候,自然在結果中user_id
也是唯一的一個。
記錄這一篇的原因是因爲一開始想的太複雜了,什麼子查詢啊,not exist
之類的,自己把問題想麻煩了,包括使用distinct
獲取數據,往錯的方向上努力,無論如何都是錯的。偏偏忘記了最常用的left join
和group by
,明明就是一條sql
就能解決的事情。
祝祖國70週年生日快樂,也祝各位國慶節快樂!
end