1. 程式人生 > >slim|lumen|laravel 【組合查詢 union】

slim|lumen|laravel 【組合查詢 union】

一。基礎概念解釋

定義:
在大多數開發中,使用一條SELECT查詢就會返回一個結果集。如果,我們想一次性查詢多條SQL語句,並將每一條SELECT查詢的結果合併成一個結果集返回。就需要用到Union操作符,將多個SELECT語句組合起來,這種查詢被稱為並(Union)或者複合查詢。

另外,在單表中使用Union比where多條件查詢較為複雜。而從多張表中獲取資料,使用Union會相對於簡單些。

組合查詢適用於下面兩種情境中:

從多個表中查詢出相似結構的資料,並且返回一個結果集

從單個表中多次SELECT查詢,將結果合併成一個結果集返回。

Union使用規則

Union有他的強大之處,詳細介紹之前,首先明確一下Union的使用注意規則。

Union必須由兩條或者兩條以上的SELECT語句組成,語句之間使用Union連結。

Union中的每個查詢必須包含相同的列、表示式或者聚合函式,他們出現的順序可以不一致(這裡指查詢欄位相同,表不一定一樣)

列的資料型別必須相容,相容的含義是必須是資料庫可以隱含的轉換他們的型別

包含重複、去除重複

union中mysql在查詢結果集中幫我們自動去除了重複的行(重複的行是李四),把兩條李四合並了。

select user_id,user_nickname,user_status from yy_user where user_status = 1 
UNION
select user_id,user_nickname,user_status from yy_user where user_id > 3

一般情況下這樣結果是好的,但是如果需要的情況下,我們可以使用Union All操作符來取消自動合併功能。

select user_id,user_nickname,user_status from yy_user where user_status = 1 
UNION ALL
select user_id,user_nickname,user_status from yy_user where user_id > 3

結果排序
注意:由於在多表組合查詢時候,可能表字段並不相同。所以,在對於結果集排序的時候需要使用檢索出來的共同欄位。

(select user_id,user_nickname,user_status from yy_user where user_status = 1) 
UNION ALL
(select user_id,user_nickname,user_status from yy_user where user_id > 3)
order by user_id desc

**上面檢索的欄位user_id必須存在於結果集中。**

多表組合查詢
大型專案中資料經常分佈在不同的表,檢索的時候需要組合查詢出來。多表查詢的時候,並不要求兩個表完全相同,只需要你檢索的欄位結構相似就可以。

select posts_id,posts_name,posts_status from yy_posts
UNION
select user_id,user_nickname,user_status from yy_user

區分多表
上一個例子中,我們組合查詢了user表和posts表。雖然結果混合在一起沒有任何問題,但是當顯示到頁面的時候,我們需要給使用者和文章不同的連結或者其他的區分。所以我們必須確定該條記錄來自於哪張表,我們可以新增一個別名來作為表名。

select posts_id,posts_name,posts_status,'users' as table_name from yy_posts
UNION
select user_id,user_nickname,user_status,'posts' as table_name from yy_user

注意SQL語句中的'users' as table_name。對應的是圖片裡的table_name,就是我們剛剛新增用於區別表的欄位。


二。專案中的實際應用

 $db = $this->db;
    $params = $request->getQueryParams();
    $coupon = $db::table("coupon as c")
        ->select('c.id','c.coupon_head','c.min_money','c.max_money','c.coupon_type','c.allow_use_client',
            'c.new_old_user','c.stock','c.start_time','c.end_time','c.created_time','c.coupon_type_text',
            $db::raw("if(time_type='2',TIMESTAMPDIFF(day,date(c.created_time),c.start_time),'') as effective_time"),
            $db::raw("if(time_type='2',TIMESTAMPDIFF(day,c.start_time,c.end_time),'') as finish_time"),
            $db::raw("if(time_type='2','領取後n天有效,有效期x天',concat(c.start_time,'~',c.end_time))as time"),
            $db::raw("concat(min_money,'~',max_money) as money"),
            $db::raw("if(c.stock='0','不限制',stock) as stock_name"),
            $db::raw("if(c.city_name='0','全國',city_name) as city"))
        ->where('c.is_delete','0');
    $model = $db::table("delivery_coupon as cc")
        ->select('cc.id','cc.coupon_head','cc.min_money','cc.max_money','cc.coupon_type','cc.allow_use_client',
            'cc.new_old_user','cc.stock','cc.start_time','cc.end_time','cc.created_time','cc.coupon_type_text',
            $db::raw("if(cc.time_type='2',TIMESTAMPDIFF(day,date(cc.created_time),cc.start_time),'') as effective_time"),
            $db::raw("if(cc.time_type='2',TIMESTAMPDIFF(day,cc.start_time,cc.end_time),'') as finish_time"),
            $db::raw("if(cc.time_type='2','領取後n天有效,有效期x天',concat(cc.start_time,'~',cc.end_time))as time"),
            $db::raw("concat(cc.min_money,'~',cc.max_money) as money"),
            $db::raw("if(cc.stock='0','不限制',stock) as stock_name"),
            $db::raw("if(cc.city_name='0','全國',city_name) as city"))
        ->where('cc.is_delete','0')
        ->unionAll($coupon)
        ->orderBy('created_time','desc');
    $count = $db::selectOne("select count(*) as count_all from (" . $model->toSql() . ") as `count_all`",$model->getBindings())->count_all;
    $coupon_all = $model
        ->skip(($params['page'] - 1) * $params['size'])->take($params['size'])
        ->get();

注意:
使用union all之後的sql語句類似於:

SELECT id FROM coupon  UNION ALL SELECT id FROM delivery_coupon order by 'created_time','desc';

查詢聯查之後中的資料量:

select count(*) from (SELECT id FROM coupon  UNION ALL SELECT id FROM delivery_coupon order by 'created_time','desc') as count;