• ThinkPHP5,使用unionAll取出两个毫无相关字段表的数据且分页


    一:首先来了解一下 union 和 unionAll

    1:取结果的并集,是否去重

    1. union:对两个结果集进行并集操作,不包括重复行,相当于distinct,同时进行默认规则的排序;

    2. unionAll:对两个结果集进行并集操作,包括重复行,即所有的结果全部显示,不管是不是重复;

    2:获取结果后的操作,是否排序

    1. union:会对获取的结果进行排序操作。

    2. unionAll:不会对获取的结果进行排序操作 。

    3:通过下面例子来粗略了解一下

    eg1:
    
    select * from A where id < 5
    union
    select * from A where id > 3 and id < 6;
    
    第一句获取:id=1234 结果集
    第二句获取:id=45 结果集
    总结果集为:123445
    但因为 union 会去重所以最终结果集为:12345
    
    eg2:
    
    select * from A where id < 5
    union all
    select * from A where id > 3 and id < 6;
    
    第一句获取:id=1234 结果集
    第二句获取:id=45 结果集
    总结果集为:123445
    union all 不会去重所以最终结果集为:123445
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    4:总结

    union all 只是合并查询结果,并不会进行去重和排序操作,在没有去重的前提下,使用 union all 的执行效率比 union 高。

    二:ThinkPHP对 UNION 和 UNIONALL 的操作说明

    UNION 操作作用于合并两个或多个 SELECT 语句的结果集。

    使用示例:

    Db::field('name')
        ->table('think_user_0')
        ->union('SELECT name FROM think_user_1')
        ->union('SELECT name FROM think_user_2')
        ->select();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    闭包用法:

    Db::field('name')
        ->table('think_user_0')
        ->union(function ($query) {
            $query->field('name')->table('think_user_1');
        })
        ->union(function ($query) {
            $query->field('name')->table('think_user_2');
        })
        ->select();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    或者

    Db::field('name')
        ->table('think_user_0')
        ->union([
            'SELECT name FROM think_user_1',
            'SELECT name FROM think_user_2',
        ])
        ->select();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    支持UNION ALL 操作,例如:

    Db::field('name')
        ->table('think_user_0')
        ->unionAll('SELECT name FROM think_user_1')
        ->unionAll('SELECT name FROM think_user_2')
        ->select();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    或者

    Db::field('name')
        ->table('think_user_0')
        ->union(['SELECT name FROM think_user_1', 'SELECT name FROM think_user_2'], true)
        ->select();
    
    • 1
    • 2
    • 3
    • 4

    每个union方法相当于一个独立的SELECT语句。

    特别注意UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。

    示例:
    通过下面的示例来具体深入了解

    现在有两个表article表和notice

    article表结构如下:
    在这里插入图片描述
    notice表结构如下:
    在这里插入图片描述

    需求:通过模糊查询标题(title)和内容(content)来综合获取article表和notice表的数据并且分页
    两个表没有任何的关联字段,且字段数也不一样,这时候考虑使用 unionALL

    $notice_array = ArticleModel::field('id,title,content,cover_img,type,video_width,video_height,video_duration,created_at,updated_at')
                ->where('title|content','LIKE','%'.$search_value.'%')
                ->unionAll("select id,title,content,created_at,updated_at from hq_notice where CONCAT(title, content) like '%$search_value%'")
                ->limit($start,$end)
                ->order('updated_at','desc')
                ->select()
                ->each(function ($item,$key){
                    $item['content'] = filterContent($item['content']);
                });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这时候会出现如下报错:

    SQLSTATE[21000]: Cardinality violation: 1222 The used SELECT statements have a different number of columns
    
    • 1

    两个表获取的列的数量不一样

    根据需求还需要判断类型,此时先将article的查询语句添加一个数据表不存在的字段 ISA_N 默认值为 Article

    ->field('id,...,"不存在的字段值" as 不存在的字段名')
    
    ArticleModel::field('id,title,content,cover_img,"Article" as ISA_N,type,video_width,video_height,video_duration,created_at,updated_at')
    
    • 1
    • 2
    • 3

    并且 notice 表的获取字段数量也要保持一样,添加默认值

    ->unionAll("select id,title,content,'img','Notice','1','width','height','duration',created_at,updated_at from hq_notice)
    
    • 1

    字段对应为:

    id=>id,title=>title,content=>content,cover_img=>'img',ISA_N=>'Notice',type=>'1',video_width=>'width',video_height=>'height',video_duration=>'duration',created_at=>created_at,updated_at=>updated_at
    
    • 1

    最后整合的语句如下:

    $notice_array = ArticleModel::field('id,title,content,cover_img,"Article" as ISA_N,type,video_width,video_height,video_duration,created_at,updated_at')
                ->where('title|content','LIKE','%'.$search_value.'%')
                ->unionAll("select id,title,content,'img','Notice','1','width','height','duration',created_at,updated_at from hq_notice where CONCAT(title, content) like '%$search_value%'")
                ->limit($start,$end)
                ->order('updated_at','desc')
                ->select()
                ->each(function ($item,$key){
                    $item['content'] = filterContent($item['content']);
                });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结果为:
    在这里插入图片描述
    没有的字段填充的是默认的值

    补充:

    concat函数

    可以使用MySQL的concat函数,将多个字段合并成一个字段进行匹配。以下是示例语句:
    SELECT * FROM table_name WHERE CONCAT(column1, column2) LIKE ‘%keyword%’
    其中CONCAT函数将column1和column2合并成一个字段进行匹配,%keyword%表示需要匹配的关键字。

    相当于使用or操作符
    可以使用or操作符来连接多个like子句,让查询同时匹配多个字段。以下是示例语句:
    SELECT * FROM table_name WHERE column1 LIKE ‘%keyword%’ OR column2 LIKE ‘%keyword%’
    其中table_name为表名,column1和column2是需要匹配的字段名,%keyword%表示需要匹配的关键字。

  • 相关阅读:
    Redis简单介绍
    微同城生活圈小程序源码系统 专业搭建本地生活服务的平台 带完整搭建教程
    【面试题精讲】finally 中的代码一定会执行吗?
    10.18~10.22数电第二次实验
    『力扣每日一题16』:存在重复元素
    y118.第七章 服务网格与治理-Istio从入门到精通 -- Istio流量治理快速入门(四)
    谷歌发布基于声学建模的无限虚拟房间增强现实鲁棒语音识别技术
    python练习题集锦之一
    学习鸿蒙基础(11)
    这些嵌入式知识助你秋招,也助你进阶
  • 原文地址:https://blog.csdn.net/weixin_43741253/article/details/133140993