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を実行しているHerokuPostgreSQLを使用しています

また、上記のクエリを最適化できるかどうか、またはこれが不適切な形式であるかどうかもわかりません。最適化/改善できるのであれば、その方法を学びたいと思います。

4

1 に答える 1

2

提供するtablefuncモジュールcrosstab()は9.1で使用できます(ミレニアムのこちら側の他のバージョンと同様)。Herokuでは追加のモジュールをインストールできませんか?やってみました:

CREATE EXTENSION tablefunc;

使用方法の例については、マニュアルまたはこの関連する質問を参照してください:
PostgreSQLクロス集計クエリ

OR try this search - there are a couple of good answers with examples on SO.

To get you started (like most of the way ..) use this largely simplified and re-organized query as base for the crosstab() call:

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;

If your columns are defined NOT NULL, you can further simplify the CASE expressions.

If performance is crucial, you can get all aggregates in a single scan in a CTE and split values into two rows in the next step.

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;

I also demonstrate two alternative ways to build your aggregates - both built on the assumption that all columns are boolean NOT NULL. Both alternatives are syntactically shorter, but not faster. In previous testes all three methods performed about the same.

于 2013-01-30T19:39:10.087 に答える