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

测试结果

相关推荐
ss2736 小时前
PostgreSQL常见索引问题与解决方案
数据库·postgresql
小徐不徐说6 小时前
序列化与反序列化:把 C++ 对象可靠地保存下来
开发语言·数据库·c++·php
瀚高PG实验室7 小时前
发布端逻辑复制槽消失
数据库·postgresql·瀚高数据库
ss2738 小时前
PostgreSQL慢查询定位与优化
数据库·postgresql
香蕉大香蕉(06敬畏市场)8 小时前
MySQL 单点详解(07)
java·数据库·mysql·ai·博客·八股
smilejingwei9 小时前
TRAE 插件上新 | SQLazy:让 AI 写出可信复杂 SQL
数据库·人工智能·sql
我要见SA姐19 小时前
GitHub Actions 自动化:5 个真实运维提效案例
运维·数据库·机器学习·oracle·回归
QXWZ_IA10 小时前
边坡监测预算有限时的建设顺序:虚拟基准站与成本账
网络·数据库
这个DBA有点耶11 小时前
1亿条向量内存降95.4%,延迟降80%:金仓AI原生内核真能解决RAG痛点?
数据库·人工智能·开源
Y38153266211 小时前
用 httpx 写 SerpBase 异步客户端:连接池与超时配置
运维·服务器·数据库