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

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

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

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

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

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

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

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

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

php 复制代码
eg1:

select * from A where id < 5
union
select * from A where id > 3 and id < 6;

第一句获取:id=1、2、3、4 结果集
第二句获取:id=4、5 结果集
总结果集为:1、2、3、4、4、5
但因为 union 会去重所以最终结果集为:1、2、3、4、5

eg2:

select * from A where id < 5
union all
select * from A where id > 3 and id < 6;

第一句获取:id=1、2、3、4 结果集
第二句获取:id=4、5 结果集
总结果集为:1、2、3、4、4、5
union all 不会去重所以最终结果集为:1、2、3、4、4、5

4:总结

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

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

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

使用示例:

php 复制代码
Db::field('name')
    ->table('think_user_0')
    ->union('SELECT name FROM think_user_1')
    ->union('SELECT name FROM think_user_2')
    ->select();

闭包用法:

php 复制代码
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();

或者

php 复制代码
Db::field('name')
    ->table('think_user_0')
    ->union([
        'SELECT name FROM think_user_1',
        'SELECT name FROM think_user_2',
    ])
    ->select();

支持UNION ALL 操作,例如:

php 复制代码
Db::field('name')
    ->table('think_user_0')
    ->unionAll('SELECT name FROM think_user_1')
    ->unionAll('SELECT name FROM think_user_2')
    ->select();

或者

php 复制代码
Db::field('name')
    ->table('think_user_0')
    ->union(['SELECT name FROM think_user_1', 'SELECT name FROM think_user_2'], true)
    ->select();

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

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

示例:

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

现在有两个表article 表和notice

article表结构如下:

notice表结构如下:

需求:通过模糊查询标题(title)和内容(content)来综合获取article表和notice表的数据并且分页

两个表没有任何的关联字段,且字段数也不一样,这时候考虑使用 unionALL

php 复制代码
$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']);
            });

这时候会出现如下报错:

php 复制代码
SQLSTATE[21000]: Cardinality violation: 1222 The used SELECT statements have a different number of columns

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

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

php 复制代码
->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')

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

php 复制代码
->unionAll("select id,title,content,'img','Notice','1','width','height','duration',created_at,updated_at from hq_notice)

字段对应为:

php 复制代码
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

最后整合的语句如下:

php 复制代码
$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']);
            });

结果为:

没有的字段填充的是默认的值

补充:

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%表示需要匹配的关键字。

相关推荐
YOU OU8 小时前
Redis基础常识与命令
数据库·redis·缓存
Database_Cool_10 小时前
OLTP 和 OLAP 区别详解:分析型数据库和事务型数据库怎么选(附阿里云 AnalyticDB MySQL 选型指南)
数据库·mysql·阿里云
爱写代码的阿森10 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
Database_Cool_11 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
姜太小白12 小时前
【MySQL】 索引优化实战:解决 WHERE 等值 + IS NULL 查询,TEXT 字段报错 1167 的完整指南
数据库·mysql
窝子面12 小时前
手搓最简前后端协作-node
javascript·数据库
吳所畏惧12 小时前
宝塔面板Redis密码修改指南:SSH命令修改 vs 面板UI界面修改,哪个更靠谱?
运维·服务器·数据库·redis·缓存·ssh
DFT计算杂谈12 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
HPFBoy12 小时前
log4net 数据库存日志正确配置
数据库