次の2つのテーブルがあります。
create table first (id int, name varchar(20));
create table second (id int, value char(1),fid int);
これらのテーブルには次のレコードがあります。
insert into first values (1,'Ahmad'),(2,'Sami'),(3,'Khan');
insert into second values
(1,'a',1)
, (2,'b',1)
, (3,'c',2)
, (4,'d',1)
, (5,'e',2)
, (6,'f',3);
単一行のテーブルsecond
に一致するレコードがあるテーブルfirst
からレコードを選択したい。
望ましい出力は次のようになります。
id |名前|値|値|値 --- + ------- + ------- + ------- + ------- 1 |アフマド| a | b | d 2 |サミ| c | e | 3 |カーン| f | |
テーブルfirst
の単一のレコードの値の数は制限されず、テーブルn
の単一のレコードのfirst
の数の値が存在する可能性があります。
n
は不明ですが、テーブルvalue
に一致するレコードがあるテーブルsecond
の各値に対して列first
を繰り返す必要があります。上記のようなテーブル全体が必要ですThe desired result
。テーブルsecond
によって参照される行のみが必要です。 Postgresのバージョンが最新になります。
実際、以来
テーブル
n
の単一のレコードにfirst
個の値が存在する可能性があります。
返す列の数はnot完全に任意です。最大数の列があり、これはクリーンな解決策を持っています- Postgresがテーブルに許可するよりも多くの列がない場合:
カラムのタイプに応じて250〜1600
ちなみに、通常、third
テーブルにはvalue
のすべての可能な値がリストされており、そのすべてが古典的な多対多の関係を実装しています。
CASE
ステートメントを使用できます。より洗練された方法として、追加モジュールtablefunc
のcrosstab()
関数を使用できます。慣れていない場合は、最初に以下の基本的な手順をお読みください。
実際の値の右側の列はNULLで埋められます。最大5つの可能な値を想定し、この設定に基づいて構築します。
_CREATE TABLE first (id int, name text);
CREATE TABLE second (id int, value "char", fid int);
INSERT INTO first VALUES
(1,'Ahmad')
, (2,'Sami')
, (3,'Khan')
, (4,'Nobody'); -- Added to demonstrate difference
INSERT INTO second VALUES
(1,'a',1)
, (2,'b',1)
, (3,'c',2)
, (4,'d',1)
, (5,'e',2)
, (6,'f',3);
_
crosstab(text)
(1パラメータ形式)を使用して、もう一度テーブルfirst
に結合します。
_SELECT id, f.name, value1, value2, value3, value4, value5
FROM crosstab(
'SELECT f.id, 1 AS dummy_category, s.value
FROM first f
JOIN second s ON s.fid = f.id
ORDER BY f.id, s.value'
) ct (id int
, value1 "char", value2 "char", value3 "char", value4 "char", value5 "char")
JOIN first f USING (id);
_
または、crosstab(text, text)
(2パラメータ形式)を使用して、値のダミーカテゴリを生成します。
_SELECT *
FROM crosstab(
'SELECT f.id, f.name
, row_number() OVER (PARTITION BY f.id ORDER BY s.value) AS dummy_category
, s.value
FROM first f
JOIN second s ON s.fid = f.id
ORDER BY f.id, s.value'
, ('SELECT generate_series(1,5)')
) ct (id int, name text
, value1 "char", value2 "char", value3 "char", value4 "char", value5 "char");
_
結果はどちらの方法でも同じです。
_ id | name | value1 | value2 | value3 | value4 | value5
----+-------+--------+--------+--------+--------+--------
1 | Ahmad | a | b | d | |
2 | Sami | c | e | | |
3 | Khan | f | | | |
_
テーブルfirstからall行を含める場合は、 _LEFT [OUTER] JOIN
_:
_ ...
LEFT JOIN second s ON s.fid = f.id
...
_
次に、上記の例の結果行を1つ追加します。
_ 4 | Nobody | | | | |
_
これは、通常のSQLを使用して行の値に基づいて任意の数の列を取得することはできません。
あなたはあなたが望むものと同様の結果を得ることができます:
Select f.id, f.name, array_agg(s.value)
From first f inner join second s on f.id = s.fid
Group by f.id, f.name
これは3つの列を返し、3番目の列は配列になります。