union當第一個表不存在數據時,再查詢第二個表

前言

在很多業務場景中,我們會出現如下的需求:在某一個表中查詢“熱”數據,查詢不到再去另一個表中查找“冷”數據,此時我們如何通過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》中,看到此之前沒涉獵到的知識點,感覺挺有收穫的,故在此分享下!

閒時多讀書,拒絕負能量。武漢加油,中國加油!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章