1

如何使用交叉表将以下查询转换为数据透视表?

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

另外,我不确定我的上述查询是否可以优化,或者这是否是糟糕的形式。如果可以优化/改进它,我很想学习如何。

4

1 回答 1

2

提供的tablefunc模块crosstab()可用于 9.1(就像千禧年的任何其他版本一样)。Heroku 不让你安装额外的模块吗?你有没有尝试过:

CREATE EXTENSION tablefunc;

有关如何使用它的示例,请参阅手册或此相关问题:
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. 这两种选择在语法上都更短,但不是更快。在之前的测试中,所有三种方法的表现都差不多。

于 2013-01-30T19:39:10.087 回答