これがcrosstab()
で実行できるかどうかはわかりません。 この質問/回答 を参照として使用していますが、クエリをまとめるのが困難です。
私のテーブルは次のようになっていますが、週の列に50以上の異なる値があるだけです。
+------+----+--------+---------+--------+
| week | id | param1 | param2 | param3 |
+------+----+--------+---------+--------+
| 1 | 1 | 13 | 10 | 12 |
| 1 | 2 | 12 | 11 | 44 |
| 2 | 1 | 34 | 33 | 3 |
| 2 | 2 | 3 | 44 | 3 |
+------+----+--------+---------+--------+
次のように回転させたい:
+----+----------+-----------+----------+----------+----------+----------+-----+
| id | w1param1 | w1param2 | w1param3 | w2param1 | w2param2 | w2param3 | ... |
+----+----------+-----------+----------+----------+----------+----------+-----+
| 1 | 13 | 10 | 12 | 34 | 33 | 3 | ... |
| 2 | 12 | 11 | 44 | 3 | 44 | 3 | ... |
+----+----------+-----------+----------+----------+----------+----------+-----+
ここで、週列はパラメーター列の番号付けに使用され、行は列になります。
(2番目の形式の)crosstab()
関数は、これらの列を入力として期待します。
row_name
列extra
列category
列value
列見る:
特定の問題は、3value
列を一度に処理しようとしていることです(param1
、param2
、param3
)。入力テーブルはすでに「半分ピボット」されています。これを解決するにはさまざまな方法があります。 3つのクロス集計クエリを結合するのがおそらく最もクリーンです。 5週間のデモ:
SELECT *
FROM crosstab(
'SELECT id, week, param1
FROM tbl
ORDER BY 1,2'
, 'SELECT generate_series(1,5)'
) ct1 (id int, w1p1 int, w1p2 int, w1p3 int, w1p4 int, w1p5 int)
JOIN crosstab(
'SELECT id, week, param2
FROM tbl
ORDER BY 1,2'
, 'SELECT generate_series(1,5)'
) ct2 (id int, w2p1 int, w2p2 int, w2p3 int, w2p4 int, w2p5 int) USING (id)
JOIN crosstab(
'SELECT id, week, param3
FROM tbl
ORDER BY 1,2'
, 'SELECT generate_series(1,5)'
) ct3 (id int, w3p1 int, w3p2 int, w3p3 int, w3p4 int, w3p5 int) USING (id)
dbfiddle ここ
[INNER] JOIN
は安全です。すべてのインスタンスが同じ週のid
sを返すことが保証されているためです。それ以外の場合はFULL JOIN
。
50週間を超えると、150カラム以上になります。それは本当にあなたが望むことですか?
列数が多いか不明な(動的)クロス集計クエリには、これらの列をクエリで列挙する必要があるという問題があります。
これを回避する方法はいくつかあります。
動的SQLですべての列をピボットするクエリを生成します。その場合、サーバーへの2つのラウンドトリップが必要です。1つはクエリを生成するため、もう1つはクエリを実行するためです。
psqlが\ crosstabviewコマンドで実行できるように、クライアント側のピボット
質問の場合、生成されたクエリは次のようになります。
_ SELECT id,
sum(case when week=1 then param1 end) AS w1param1,
sum(case when week=1 then param2 end) AS w1param2,
sum(case when week=1 then param3 end) AS w1param3,
sum(case when week=2 then param1 end) AS w2param1,
... repeated until w50param3 or somesuch
FROM tablename GROUP BY id ORDER BY id;
_
crosstab()
はこのメソッドでは使用されないことに注意してください。
このターゲットクエリは、次のクエリを含む動的ステートメントとして生成できます。これは、基本的には週数と(1,2,3)のクロス積であり、SQLのビットがいくつかあります。
_SELECT concat('SELECT id,',
(SELECT string_agg(clause, ',') FROM (
SELECT format('sum(case when week=%s then param%s end) AS w%sparam%s',
week, p, week, p) AS clause
FROM (SELECT DISTINCT week FROM tablename) s,
generate_series(1,3) as p
ORDER BY week,p
) clauses),
' FROM tablename GROUP BY id ORDER BY id'
) AS pivot_query;
_
プログラミング言語では、このクエリを実行し、結果(単一行、単一列の文字列)をフェッチして、その結果をSQLクエリとして実行すると、150以上の列を持つ予期されるピボットデータが生成されます。
Psqlでは、これは\ gsetと変数を介して行うことができます
_ =# SELECT concat(
... etc...
) AS pivot_query \gset
=# :pivot_query \g
_
結果をパディングや装飾なしでファイルに保存するには、次の設定を使用します。
_=# \pset footer off \o /path/to/file.txt \pset format unaligned
_
フィールド区切り文字は、_\pset fieldsep
_または_\F
_でも設定できます。
結果がファイルに格納されたら、_\o
_のみを使用して、出力をターミナルにリダイレクトします。
クライアント側のpsql
のみのソリューションは、_\crosstabview
_(psql 9.6+)の方が簡単です。
クエリはまったく異なります。最初に列を「アンピボット」して(_UNION ALL
_サブクエリを使用して)、列_param1..2..3
_を取得して、2番目の列に目的の列名を取得し、3番目の列にこれらのパラメータの対応する値を取得します。列、および4番目の列のピボットデータの目的の列の順序。
これは次のようになります。
_SELECT id, 'w' || week || 'param' || p, val,
row_number() over (order by week,p) as rn
FROM (
SELECT id, week, 1 AS p, param1 AS val FROM tablename
UNION ALL
select id, week, 2 AS p, param2 AS val FROM tablename
UNION ALL
select id, week, 3 AS p, param3 AS val FROM tablename
) s ORDER BY id \crosstabview 1 2 3 4
_
ファイルにリダイレクトするには、前のソリューションと同じです。おそらく、装飾、パディング、フッターを削除し、セパレーターを選択します。