当前位置: 首页 > news >正文

记一次postgresql拼接函数string_agg() 和row_number() 使用

PG两个函数使用需求和简单介绍

  • 需求背景介绍
    • 第一个需求背景是这样的
    • 需求升级一下
    • 接下来讲讲STRING_AGG()
      • 基本语法
      • 排序
    • 然后我们再说说ROW_NUMBER()
      • 基本语法
      • 使用 row_number() over (partition by) 进行分组统计
      • 使用 row_num限定每组数量

需求背景介绍

第一个需求背景是这样的

我需要从数据库查询企业的一些信息,其中包括企业曾用名,企业曾用名可能有多个,但是企业主体信息只有一个,且不在同一张表中;我还需要取出另一个表中关联的电话和邮箱,其中电话和邮箱有多个,实际为年份不同可能不一样,也可能为空,我需要取不为空的最新年份的数据。
数据库PG,要求所有曾用名,分隔,企业查询为模糊查询。

SELECTC.entname as entname,C.uniscid as uniscid,cb.dom as dom,cb.esdate as esdate,cb."name" as frname,cb.regcap as regcap,STRING_AGG ( cm.altbe, ',' ) as nameBefore,A.email as email,A.tel as tel,co.name as entstatusFROMcompanyC LEFT JOIN company_basic cb ON C.entid = cb.entidLEFT JOIN company_modify cm ON C.entid = cm.entidleft join code_ex02 co on cb.entstatus = co.codeLEFT JOIN (SELECTcc.entid AS entid,ca.email AS email,ca.tel AS tel,ROW_NUMBER () OVER ( PARTITION BY cc.ID ORDER BY ca.email DESC ) AS rnFROMcompany ccLEFT JOIN company_ar ca ON cc.entid = ca.entidWHEREcc.entname LIKE concat('%',#{companyName},'%')AND ca.email IS NOT NULLAND ca.tel IS NOT NULLORDER BYca.ancheyear DESC) A ON C.entid = A.entid AND A.rn = 1WHEREC.entname LIKE concat('%',#{companyName},'%')AND cm.altitem = '01'GROUP BYC.entname,C.uniscid,cb.dom,cb.esdate,cb."name",cb.regcap,A.email,A.tel,co.name

可以看到,关联company_ar表,查曾用名,需要使用row_number()函数,取第一行,这就需要先包一层,取rn=1
这里为什么不能使用limit 1,原因是这里是模糊查询,查出来的是多家公司,我需要每个公司取第一行,limit 1不能满足。


需求升级一下

我需要从数据库查询企业的一些信息,其中包括企业曾用名,企业曾用名可能有多个,且是分开的,数据大概像下图
既有可能有多个,每个还都是分开的,需要拼接,每个完整的企业曾用名使用,分隔,但是企业主体信息只有一个,且不在同一张表中;我还需要取出另一个表中关联的电话和邮箱,其中电话和邮箱有多个,实际为年份不通可能不一样,也可能为空,我需要取不为空的最新年份的数据。
数据库PG,要求所有曾用名先按照id排序之后拼接再,分隔,企业查询为模糊查询。

在这里插入图片描述

SELECTC.entname as entname,C.uniscid as uniscid,C.dom as dom,C.esdate as esdate,C."name" as frname,C.regcap as regcap,STRING_AGG ( C.content_text, ',' ) as nameBefore,C.email as email,C.tel as tel,c.entstatus as entstatusFROM(SELECTC.entname,C.uniscid,cb.dom,cb.esdate,cb."name",cb.regcap,STRING_AGG ( ccrc.content_text, '' ORDER BY ccrc.ID ) AS content_text,A.email,A.tel,cb.entstatus as entstatusFROMcompanyC LEFT JOIN company_basic cb ON C.ID = cb.entidLEFT JOIN company_change_record ccr ON ccr.entid = C.IDAND ccr.altitem = '名称变更'LEFT JOIN company_change_record_content ccrc ON ccr.ID = ccrc.company_change_record_idAND ccrc.company_chang_type = 0LEFT JOIN (SELECTcc.ID AS ID,ca.email AS email,ca.tel AS tel,ROW_NUMBER () OVER ( PARTITION BY cc.ID ORDER BY ca.email DESC ) AS rnFROMcompany ccLEFT JOIN company_ar ca ON cc.ID = ca.entidWHEREcc.entname LIKE concat('%',#{companyName},'%')AND ca.ancheyear IS NOT NULLAND ca.email IS NOT NULLAND ca.tel IS NOT NULLORDER BYca.ancheyear DESC) A ON A.ID = C.IDAND A.rn = 1WHEREC.entname LIKE concat('%',#{companyName},'%')GROUP BYC.entname,C.uniscid,cb.dom,cb.esdate,cb."name",cb.regcap,A.email,A.tel,cb.entstatus,ccrc.company_change_record_id) CGROUP BYC.entname,C.uniscid,C.dom,C.esdate,C."name",C.regcap,C.email,C.tel,c.entstatus

这个sql写起来就比之前的sql又多一层,曾用名字段需要拼接两次,且企业曾用名拼接是需要按照id排序的。

接下来讲讲STRING_AGG()

基本语法

string_agg(column_name, separator)  

前边column_name是想要拼接的字段名,后边separator是分隔符。
像上边sql中

STRING_AGG ( C.content_text, ',' )

将content_text 以,分隔
使用像string_agg() 聚合函数,需要使用group by将不需要聚合的字段都写在group by中。

排序

这里升级版需求需要排序然后再聚合拼接,就需要加上order by
这里直接在函数中加上就可以

STRING_AGG ( ccrc.content_text, '' ORDER BY ccrc.ID )

这样就可以实现。

然后我们再说说ROW_NUMBER()

row_number() 函数是 PostgreSQL 中的一个窗口函数,它的作用是为每一行分配一个唯一的序号。当涉及到分组统计时,我们可以使用 row_number() 函数结合 over (partition by) 子句来实现。

基本语法

ROW_NUMBER() OVER ([PARTITION BY partition_expression, ... ]ORDER BY sort_expression [ASC | DESC], ...
)

partition_expression需要是唯一ID,order by 按照自己的实际需求

使用 row_number() over (partition by) 进行分组统计

像上边sql中,

ROW_NUMBER () OVER ( PARTITION BY cc.ID ORDER BY ca.email DESC 

我们首先使用 PARTITION BY cc.ID 对数据进行分组,然后使用 ORDER BY email DESC 对每个分组内的数据按照邮箱(其实是随便选的,因为这里需求不做强制要求)降序排序。接着,我们使用 ROW_NUMBER() 函数为每一行分配一个唯一的序号。最后,我们将结果输出到一个新的表中。

使用 row_num限定每组数量

像上边sql中,已经对结果进行了分组统计

ROW_NUMBER () OVER ( PARTITION BY cc.ID ORDER BY ca.email DESC 

最终关联的时候取rn = 1,就可以限定数量,这里可以使用<= 等等限定数量。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 区间预测 | Matlab实现LSTM-ABKDE长短期记忆神经网络自适应带宽核密度估计多变量回归区间预测
  • LeetCode110. 平衡二叉树
  • 国标GB/T 28181详解:校时流程详细说明
  • java asm使用切面
  • Next.js Tailwind CSS UI组件
  • Python基础——字符串
  • DeepSpeed入门
  • 度小满金融大模型的应用创新
  • AIGC作答《2024年高考作文|新课标I卷》能拿多少分?
  • 测试基础11:测试用例设计方法-等价类划分
  • 定个小目标之刷LeetCode热题(14)
  • 在线按模板批量生成文本工具
  • Golang | Leetcode Golang题解之第134题加油站
  • Redis实战篇02
  • 探索智慧商场的功能架构与应用
  • ES6指北【2】—— 箭头函数
  • JavaScript 如何正确处理 Unicode 编码问题!
  • Apache的基本使用
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • express + mock 让前后台并行开发
  • happypack两次报错的问题
  • Javascript 原型链
  • javascript从右向左截取指定位数字符的3种方法
  • Linux链接文件
  • ReactNativeweexDeviceOne对比
  • SpringCloud集成分布式事务LCN (一)
  • Transformer-XL: Unleashing the Potential of Attention Models
  • webgl (原生)基础入门指南【一】
  • 大型网站性能监测、分析与优化常见问题QA
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 前端
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 用mpvue开发微信小程序
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • #Datawhale X 李宏毅苹果书 AI夏令营#3.13.2局部极小值与鞍点批量和动量
  • #mysql 8.0 踩坑日记
  • (0)Nginx 功能特性
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (Forward) Music Player: From UI Proposal to Code
  • (k8s)kubernetes集群基于Containerd部署
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (定时器/计数器)中断系统(详解与使用)
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (接上一篇)前端弄一个变量实现点击次数在前端页面实时更新
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (算法二)滑动窗口
  • (学习日记)2024.01.19
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)C语言家族扩展收藏 (转)C语言家族扩展