postgresql中如何把列中的每一行数据变成列的标题

postgresql中如何把列中的每一行数据变成列的标题

测试表

sql 复制代码
CREATE TABLE public.benefits (
	id int4 NOT NULL,
	workplace varchar(255) NULL,
	province varchar(255) NULL,
	benefits int4 NULL,
	CONSTRAINT offer_benefits_pkey PRIMARY KEY (id)
);
sql 复制代码
INSERT INTO public.benefits
(id, workplace, province, benefits)
VALUES(1, '合肥', '合肥', 0);
INSERT INTO public.benefits
(id, workplace, province, benefits)
VALUES(2, '合肥', '上海', 1000);
INSERT INTO public.benefits
(id, workplace, province, benefits)
VALUES(3, '合肥', '北京', 1000);
INSERT INTO public.benefits
(id, workplace, province, benefits)
VALUES(4, '合肥', '西安', 1000);
INSERT INTO public.benefits
(id, workplace, province, benefits)
VALUES(5, '上海', '上海', 0);
INSERT INTO public.benefits
(id, workplace, province, benefits)
VALUES(6, '上海', '合肥', 1000);
INSERT INTO public.benefits
(id, workplace, province, benefits)
VALUES(7, '上海', '北京', 1000);
INSERT INTO public.benefits
(id, workplace, province, benefits)
VALUES(8, '上海', '西安', 1000);

方法一

在 PostgreSQL 中,如果你想将表中的某一列的数据变成列标题(通常被称为"列转行"或"交叉表"操作)

你可以使用 crosstab 函数,这个函数是 PostgreSQL 提供的 tablefunc 扩展中的一部分

安装 tablefunc 扩展

sql 复制代码
CREATE EXTENSION IF NOT EXISTS tablefunc;

安装成功,可以在扩展中查看

使用 crosstab 函数

sql 复制代码
SELECT *
FROM crosstab(
    $$SELECT workplace, province, benefits FROM postgres.public.benefits  
    ORDER BY workplace, province$$
) AS ct (workplace varchar, "合肥" int, "上海" int, "北京" int, "西安" int);

在这里,crosstab 函数的第一个参数是一个 SQL 查询,返回的结果必须包含三列:行标题列(workplace)、列标题列(province)和数值列(benefits )。第二个参数是结果表的列定义,必须明确指定每个新列的名称和数据类型。

注意事项

  • 列标题必须事先知道:在定义 crosstab 函数的输出列时,必须提前知道所有可能的列标题(即 province列的所有可能值)。
  • 数据类型匹配:定义的列数据类型必须与原始表中的数据类型匹配。
  • 数据量大的情况:如果有很多列(即 province的不同值很多),这个过程可能变得复杂,可以考虑动态生成列名和数据类型。

测试结果

方法二

除了使用 crosstab 函数,PostgreSQL 还可以使用条件聚合(conditional aggregation)来实现相同的效果。这种方法不需要安装 tablefunc 扩展,直接通过 SQL 语句中的聚合函数和 CASE 语句来实现。

sql 复制代码
SELECT
    workplace,
    MAX(CASE WHEN province = '合肥' THEN benefits ELSE 0 END) AS "合肥",
    MAX(CASE WHEN province = '上海' THEN benefits ELSE 0 END) AS "上海",
    MAX(CASE WHEN province = '北京' THEN benefits ELSE 0 END) AS "北京",
    MAX(CASE WHEN province = '西安' THEN benefits ELSE 0 END) AS "西安"
FROM
    postgres.public.benefits  
GROUP BY
    workplace;
  • MAX(CASE WHEN province = '合肥' THEN benefits ELSE 0 END): 这个表达式会在 province 为 合肥 时返回 benefits 的值,否则返回 0。然后使用 MAX 函数来获取该组中最大的值(实际上这里只有一个非零值)
  • GROUP BY workplace: 按照 workplace 列进行分组,确保每个 workplace 只有一行结果。

优点

  • 不需要安装额外的扩展。
  • 直接在标准 SQL 中实现,易于理解和维护

缺点

  • 需要手动列出所有可能的 province 值,如果 province 值很多或者动态变化,维护起来可能比较繁琐。
  • 如果有很多列,这种方法的 SQL 语句会变得很长
    这种方法适用于列数较少且固定的情况。如果 province 列的值很多且可能动态变化,使用程序化的方法生成 SQL 语句可能更加高效

测试结果

相关推荐
剩下了什么13 小时前
MySQL JSON_SET() 函数
数据库·mysql·json
山峰哥14 小时前
数据库工程与SQL调优——从索引策略到查询优化的深度实践
数据库·sql·性能优化·编辑器
较劲男子汉14 小时前
CANN Runtime零拷贝传输技术源码实战 彻底打通Host与Device的数据传输壁垒
运维·服务器·数据库·cann
java搬砖工-苤-初心不变14 小时前
MySQL 主从复制配置完全指南:从原理到实践
数据库·mysql
山岚的运维笔记16 小时前
SQL Server笔记 -- 第18章:Views
数据库·笔记·sql·microsoft·sqlserver
roman_日积跬步-终至千里17 小时前
【LangGraph4j】LangGraph4j 核心概念与图编排原理
java·服务器·数据库
汇智信科17 小时前
打破信息孤岛,重构企业效率:汇智信科企业信息系统一体化运营平台
数据库·重构
野犬寒鸦17 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法
晚霞的不甘18 小时前
揭秘 CANN 内存管理:如何让大模型在小设备上“轻装上阵”?
前端·数据库·经验分享·flutter·3d
市场部需要一个软件开发岗位19 小时前
JAVA开发常见安全问题:纵向越权
java·数据库·安全