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 语句可能更加高效

测试结果

相关推荐
九皇叔叔1 小时前
【9】PostgreSQL 之 vacuum 死元组清理
数据库·postgresql
风雅的远行者2 小时前
mysql互为主从失效,重新同步
数据库·mysql
宇钶宇夕3 小时前
S7-1200 系列 PLC 中 SCL 语言的 PEEK 和 POKE 指令使用详解
运维·服务器·数据库·程序人生·自动化
绿蚁新亭3 小时前
Spring的事务控制——学习历程
数据库·学习·spring
scilwb4 小时前
占用栅格地图数据集
数据库
时序数据说5 小时前
时序数据库的存储之道:从数据特性看技术要点
大数据·数据库·物联网·开源·时序数据库·iotdb
鸥梨菌Honevid5 小时前
QT解析文本框数据——概述
数据库·qt·mysql
今天又得骑车了6 小时前
一、MySQL 8.0 之《EXPLAIN ANALYZE 执行计划》
数据库·mysql·database
野犬寒鸦7 小时前
MyBatis-Plus 中使用 Wrapper 自定义 SQL
java·数据库·后端·sql·mybatis
我爱一条柴ya7 小时前
【AI大模型】RAG系统组件:向量数据库(ChromaDB)
数据库·人工智能·pytorch·python·ai·ai编程