透视表(Pivot Table)是一种强大的数据分析工具,能够将行数据转换为列进行交叉分析。PostgreSQL 提供了多种实现透视表功能的方法,下面我将详细介绍这些技术。
PostgreSQL 的 tablefunc
扩展提供了 crosstab
函数,这是最直接的透视表实现方式。
CREATE EXTENSION IF NOT EXISTS tablefunc;
SELECT * FROM crosstab(
'源查询SQL',
'分类值查询SQL'
) AS ct (行标识 数据类型, 列1 数据类型, 列2 数据类型, ...);
假设有销售数据表 sales:
date | product | amount
-----------+---------+-------
2023-01-01 | A | 100
2023-01-01 | B | 150
2023-01-02 | A | 200
2023-01-02 | B | 250
创建按日期透视产品销售额的报表:
SELECT * FROM crosstab(
'SELECT date, product, amount FROM sales ORDER BY 1,2',
'SELECT DISTINCT product FROM sales ORDER BY 1'
) AS ct (date date, product_a int, product_b int);
PostgreSQL 9.4+ 支持 FILTER 子句,可以更灵活地实现透视功能。
SELECT
date,
SUM(amount) FILTER (WHERE product = 'A') AS product_a,
SUM(amount) FILTER (WHERE product = 'B') AS product_b
FROM sales
GROUP BY date
ORDER BY date;
这是最兼容的方法,适用于所有PostgreSQL版本。
SELECT
date,
SUM(CASE WHEN product = 'A' THEN amount ELSE 0 END) AS product_a,
SUM(CASE WHEN product = 'B' THEN amount ELSE 0 END) AS product_b
FROM sales
GROUP BY date
ORDER BY date;
当列值不确定或很多时,可以使用动态SQL生成透视查询。
CREATE OR REPLACE FUNCTION dynamic_pivot(central_query text, headers_query text)
RETURNS SETOF record AS $$
DECLARE
headers text;
column_list text;
final_query text;
rec record;
BEGIN
-- 获取列名
EXECUTE headers_query INTO headers;
-- 构建列定义
SELECT string_agg(format('%s numeric', header), ', ')
INTO column_list
FROM (SELECT header FROM unnest(string_to_array(headers, ',')) AS h(header);
-- 构建最终查询
final_query := format('
SELECT * FROM crosstab(
%L,
%L
) AS ct(row_name text, %s)', central_query, headers_query, column_list);
-- 执行动态查询
FOR rec IN EXECUTE final_query LOOP
RETURN NEXT rec;
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
PostgreSQL 9.4+ 支持 JSON 功能,可以灵活地处理动态列。
SELECT
date,
jsonb_object_agg(product, amount) AS product_amounts
FROM sales
GROUP BY date
ORDER BY date;
crosstab
通常性能最佳FILTER
或 CASE WHEN
更灵活通过以上方法,您可以在PostgreSQL中实现各种复杂的透视表分析功能,满足业务数据分析需求。