2022-01-16 18:06:59
在PostgreSQL中使用CROSSTAB函数实现SQL透视表(行列转换),需按以下步骤操作:
1. 启用tablefunc扩展CROSSTAB函数属于tablefunc扩展,需先确保该扩展已启用:
CREATE EXTENSION IF NOT EXISTS tablefunc;
source_sql需返回三列:
示例数据表monthly_sales:
CREATE TABLE monthly_sales ( product_name VARCHAR(50), sale_month VARCHAR(10), sale_amount DECIMAL(10, 2));INSERT INTO monthly_sales (product_name, sale_month, sale_amount) VALUES('Laptop', 'Jan', 1200.00),('Laptop', 'Feb', 1500.00),('Laptop', 'Mar', 1300.00),('Mouse', 'Jan', 50.00),('Mouse', 'Feb', 60.00),('Keyboard', 'Jan', 100.00),('Keyboard', 'Mar', 110.00),('Monitor', 'Apr', 300.00);3. 定义分类查询(category_sql)category_sql需返回一列,即所有希望出现在透视表中的分类值(按顺序排序):
SELECT DISTINCT sale_month FROM monthly_sales ORDER BY 1;4. 编写CROSSTAB查询CROSSTAB函数接受两个参数:
在AS ct(...)中定义输出列名及数据类型,需与category_sql返回的分类一一对应:
SELECT *FROM CROSSTAB( -- source_sql: 准备数据,确保返回 row_name, category, value 格式 'SELECT product_name, sale_month, sale_amount FROM monthly_sales ORDER BY 1,2', -- category_sql: 定义透视表的列名 'SELECT DISTINCT sale_month FROM monthly_sales ORDER BY 1') AS ct ( product_name VARCHAR(50), "Apr" DECIMAL(10, 2), "Feb" DECIMAL(10, 2), "Jan" DECIMAL(10, 2), "Mar" DECIMAL(10, 2));
若透视列(如月份)是动态变化的,CROSSTAB的固定列名特性会导致问题。此时可采用以下方法:
方法1:动态SQL在PL/pgSQL函数中动态生成CROSSTAB查询字符串并执行:
DO $$DECLARE _sql TEXT; _months TEXT;BEGIN -- 动态获取所有月份并格式化为列定义 SELECT string_agg(quote_ident(sale_month) || ' DECIMAL(10,2)', ', ' ORDER BY sale_month) INTO _months FROM (SELECT DISTINCT sale_month FROM monthly_sales) AS distinct_months; IF _months IS NULL THEN RAISE EXCEPTION 'No months found for pivoting.'; END IF; _sql := format( 'SELECT * FROM CROSSTAB( ''SELECT product_name, sale_month, sale_amount FROM monthly_sales ORDER BY 1,2'', ''SELECT DISTINCT sale_month FROM monthly_sales ORDER BY 1'' ) AS ct (product_name VARCHAR(50), %s);', _months ); -- 执行动态生成的SQL EXECUTE _sql;END $$;方法2:JSON聚合使用PostgreSQL的JSON函数将多行数据聚合为JSON对象:
SELECT product_name, jsonb_object_agg(sale_month, sale_amount) AS monthly_dataFROM monthly_salesGROUP BY product_name;7. 为什么选择CROSSTAB?
通过以上步骤和注意事项,可高效利用CROSSTAB函数实现SQL透视表,满足数据分析中的行列转换需求。