web-dev-qa-db-ja.com

PostgreSQLのGrouping()と同等ですか?

MS SQL Serverで実行されるSQLクエリがあり、grouping()rank()およびrollup()関数/キーワードが含まれています。クエリは以下のとおりです。

これをどのようにPostgreSQLに変換できますか?

select top 100
    sum(ss_net_profit)/sum(ss_ext_sales_price) as gross_margin  
   ,i_category  
   ,i_class  
   ,grouping(i_category)+grouping(i_class) as lochierarchy  
   ,rank() over (partition by grouping(i_category)+grouping(i_class)
                             ,case when grouping(i_class) = 0 then i_category end   
                 order by sum(ss_net_profit)/sum(ss_ext_sales_price) asc
                ) as rank_within_parent  
 from  
    ssv_itemv_storev_IJGBAgg  
 where  
    d_year = 2001   
    and s_state in ('TN')  
 group by rollup(i_category,i_class)  
 order by  
    lochierarchy desc  
   ,case when (grouping(i_category)+grouping(i_class) = 0) then i_category end  
   ,rank_within_parent;   
4
vkb

ROLLUP はPostgres 9.5で実装されています。


Postgres 9.4以前の元の回答:

rollup()group by rollup(i_category,i_class)を使用すると、階層的なステップで集計されます。これはSQL ServerのISO SQL標準を拡張したもので、Postgresには実装されていません。 2つの項目の場合、標準SQLとPostgresで3つの手順が必要です。

  1. 総計
  2. _group by i_category_
  3. _group by i_category, i_class_

grouping()function はこの拡張機能に付属しており、特定の列が各行で集計されるかどうかを示します。ここでは、結果の合計とグループ合計を最初にソートするために使用されます。

rank()は標準のウィンドウ関数です Postgresでも同じように機能しますが、上記の調整のために書き直す必要があります。

_top 100__FETCH FIRST 100 ROWS ONLY_ in標準SQL に変換され、Postgresだけでなく、より短い _LIMIT 100_ (_FETCH FIRST_構文は、SQL Server for 2012+バージョンで機能します ypercubeのコメントを参照 )。この集計クエリで100行の後で切り取るのは少し奇妙です。

[〜#〜] cte [〜#〜] を使用して、以下の複数の集計で中間結果を再利用しています。 LIMITを除いて、すべてが基本的にSQL Serverでも機能するはずです。

_WITH cte AS (
   SELECT sum(ss_net_profit) AS sum_profit
        , sum(ss_ext_sales_price) AS sum_price
        , i_category, i_class
   FROM   ssv_itemv_storev_IJGBAgg
   WHERE  d_year = 2001
   AND    s_state = 'TN'
   GROUP  BY i_category, i_class
   )
SELECT sum(sum_profit)/sum(sum_price) AS gross_margin
     , NULL AS i_category, NULL AS i_class
     , 2 AS lochierarchy  
     , 1 AS rank_within_parent
FROM   cte

UNION ALL
(  -- parentheses required!
SELECT sum(sum_profit)/sum(sum_price) AS gross_margin
     , i_category, NULL AS i_class
     , 1 AS lochierarchy  
     , rank() OVER (ORDER BY sum(sum_profit)/sum(sum_price)) AS rank_within_parent
FROM   cte
GROUP  BY i_category
ORDER  BY rank_within_parent, i_category  -- last item = my addition to break ties
)

UNION ALL
(
SELECT sum_profit/sum_price AS gross_margin
     , i_category, i_class
     , 0 AS lochierarchy  
     , rank() OVER (PARTITION BY i_category
                    ORDER BY sum_profit/sum_price) AS rank_within_parent
FROM   cte
ORDER  BY i_category, rank_within_parent, i_class  -- last item = my addition to break ties
)
LIMIT 100;
_

(未テスト。)

3