如何使用交叉表将以下查询转换为数据透视表?
select (SUM(CASE WHEN added_customer=false
THEN 1
ELSE 0
END)) AS CUSTOMERS_NOT_ADDED, (SUM(CASE WHEN added_customer=true
THEN 1
ELSE 0
END)) AS CUSTOMERS_ADDED,
(select (SUM(CASE WHEN added_sales_order=false
THEN 1
ELSE 0
END))
FROM shipments_data
) AS SALES_ORDER_NOT_ADDED,
(select (SUM(CASE WHEN added_sales_order=true
THEN 1
ELSE 0
END))
FROM shipments_data
) AS SALES_ORDER_ADDED,
(select (SUM(CASE WHEN added_fulfillment=false
THEN 1
ELSE 0
END))
FROM shipments_data
) AS ITEM_FULFILLMENT_NOT_ADDED,
(select (SUM(CASE WHEN added_fulfillment=true
THEN 1
ELSE 0
END))
FROM shipments_data
) AS ITEM_FULFILLMENT_ADDED,
(select (SUM(CASE WHEN added_invoice=false
THEN 1
ELSE 0
END))
FROM shipments_data
) AS INVOICE_NOT_ADDED,
(select (SUM(CASE WHEN added_invoice=true
THEN 1
ELSE 0
END))
FROM shipments_data
) AS INVOICE_ADDED,
(select (SUM(CASE WHEN added_ra=false
THEN 1
ELSE 0
END))
FROM shipments_data
) AS RA_NOT_ADDED,
(select (SUM(CASE WHEN added_ra=true
THEN 1
ELSE 0
END))
FROM shipments_data
) AS RA_ADDED,
(select (SUM(CASE WHEN added_credit_memo=false
THEN 1
ELSE 0
END))
FROM shipments_data
) AS CREDIT_MEMO_NOT_ADDED,
(select (SUM(CASE WHEN added_credit_memo=true
THEN 1
ELSE 0
END))
FROM shipments_data
) AS CREDIT_MEMO_ADDED
FROM shipments_data;
此查询以标准行格式提供数据,但我希望以下列格式将其显示为数据透视表:
Added Not_Added
Customers 100 0
Sales Orders 50 50
Item Fulfillemnts 0 100
Invoices 0 100
...
我正在使用运行v9.1.6的Heroku PostgreSQL
另外,我不确定我的上述查询是否可以优化,或者这是不是很糟糕。如果可以优化/改进,我很乐意学习如何。
答案 0 :(得分:2)
提供crosstab()
的{{3}}模块可用于9.1(与千禧年这一侧的任何其他版本一样)。 Heroku不允许你安装额外的模块吗?你试过了吗?
CREATE EXTENSION tablefunc;
有关如何使用它的示例,请参阅tablefunc或此相关问题:
the manual
或PostgreSQL Crosstab Query - 关于SO的例子,有几个很好的答案。
为了让您入门(就像大多数情况一样..)使用这个大大简化和重新组织的查询作为crosstab()
调用的基础:
SELECT 'added'::text AS col
,SUM(CASE WHEN added_customer THEN 1 ELSE 0 END) AS customers
,SUM(CASE WHEN added_sales_order THEN 1 ELSE 0 END) AS sales_order
,SUM(CASE WHEN added_fulfillment THEN 1 ELSE 0 END) AS item_fulfillment
,SUM(CASE WHEN added_invoice THEN 1 ELSE 0 END) AS invoice
,SUM(CASE WHEN added_ra THEN 1 ELSE 0 END) AS ra
,SUM(CASE WHEN added_credit_memo THEN 1 ELSE 0 END) AS credit_memo
FROM shipments_data
UNION ALL
SELECT 'not_added' AS col
,SUM(CASE WHEN NOT added_customer THEN 1 ELSE 0 END) AS customers
,SUM(CASE WHEN NOT added_sales_order THEN 1 ELSE 0 END) AS sales_order
,SUM(CASE WHEN NOT added_fulfillment THEN 1 ELSE 0 END) AS item_fulfillment
,SUM(CASE WHEN NOT added_invoice THEN 1 ELSE 0 END) AS invoice
,SUM(CASE WHEN NOT added_ra THEN 1 ELSE 0 END) AS ra
,SUM(CASE WHEN NOT added_credit_memo THEN 1 ELSE 0 END) AS credit_memo
FROM shipments_data;
如果您的列已定义NOT NULL
,则可以进一步简化CASE
表达式。
如果效果至关重要,您可以在CTE中的单次扫描中获取所有聚合 ,并在下一步中将值拆分为两行。
WITH x AS (
SELECT count(NULLIF(added_customer, FALSE)) AS customers
,sum(added_sales_order::int) AS sales_order
...
,count(NULLIF(added_customer, TRUE)) AS not_customers
,sum((NOT added_sales_order)::int) AS not_sales_order
...
FROM shipments_data
)
SELECT 'added'::text AS col, customers, sales_order, ... FROM x
UNION ALL
SELECT 'not_added', not_customers, not_sales_order, ... FROM x;
我还演示了构建聚合的两种替代方法 - 都建立在假设所有列都是 boolean NOT NULL
的基础上。两种选择都在语法上更短,但不会更快。在之前的测试中,所有三种方法的表现基本相同。