前言
在很多業務場景中,我們會出現如下的需求:在某一個表中查詢“熱”數據,查詢不到再去另一個表中查找“冷”數據,此時我們如何通過sql語句實現呢?
正文
-
首先,創建student和student_2兩個表,如下:
CREATE TABLE `student` ( `id` bigint(20) NOT NULL, `name` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB
CREATE TABLE `student_2` ( `id` bigint(20) NOT NULL, `name` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB
-
在student表和student_2表分別插入數據,如下:
+----+------+ | id | name | +----+------+ | 1 | haha | | 2 | hehe | +----+------+
+----+------+ | id | name | +----+------+ | 2 | wewe | | 3 | wowo | +----+------+
-
前情完成,開始測試,首先在student和student_2中查詢id爲2的數據,如下:
select * from student where id=2 union all select * from student_2 where id=2;
+----+------+ | id | name | +----+------+ | 2 | hehe | | 2 | wewe | +----+------+
可以發現,即使在student表中已經找到了記錄,上面的sql還是會再去student_2表中查詢id=2爲數據;
-
此時,引入一個自定義變量@found,我們通過GREATEST函數和found變量來實現以上的需求
- GREATEST函數:求的是某幾列中的最大值,橫向求最大(一行記錄),如greatest (a,b,c,d,d)
select greatest(@found:=-1,id) as id,name from student where id=2 union all select id,name from student_2 where id=2 and @found is null;
發現以上sql是可以實現功能的
+----+------+ | id | name | +----+------+ | 2 | hehe | +----+------+
但是,當使用該sql查詢id爲3的命令時,發現empty set,不合理啊?student表中找不到,應該要會返回student_2表中的數據啊,此時我們查看found的值,如下:
+--------+ | @found | +--------+ | -1 | +--------+
發現found設置爲-1後需要還原置null,否則影響下一步sql;
-
修改以上sql如下:
select greatest(@found:=-1,id) as id,name from student where id=3 union all select id,name from student_2 where id=3 and @found is null union all select 1,'reset' from dual where (@found:=NULL) is not null;
解釋下:
- DUAL:爲一個mysql提供進行簡單操作的表,如,可以進行四則運算:select 100*199 from dual,我們再次通過dual,判斷當found不爲Null時來重設found的值爲null;
- 爲什麼使用union all也不使用union:如果沒有all關鍵字,mysql會給臨時表加上distinct,會導致整個臨時表的數據做唯一性檢查,代價非常高。所以,除非確實需要服務器消除重複的行,否則使用union all會更高效點。
+----+------+ | id | name | +----+------+ | 3 | wowo | +----+------+
驗證成功,大功告成!
總結
假期放縱了,已許久沒更博。
此次在看《高性能Mysql》中,看到此之前沒涉獵到的知識點,感覺挺有收穫的,故在此分享下!
閒時多讀書,拒絕負能量。武漢加油,中國加油!