スタンドアロンのVALUES
式PostgreSQLは、データ型がどうあるべきかを知りません。単純な数値リテラルを使用すると、システムは一致する型を想定できます。ただし、他の入力(NULL
など)を使用する場合 )すでに知っているように、明示的にキャストする必要があります。
pg_catalog
をクエリできます (高速ですが、PostgreSQL固有)またはinformation_schema
(低速ですが標準のSQL)適切なタイプのステートメントを見つけて準備します。
または、これらの単純な「トリック」の1つを使用できます(最後のに最適なものを保存しました) ):
0。 LIMIT 0
の行を選択します 、UNION ALL VALUES
で行を追加します
UPDATE foo f
SET x = t.x
, y = t.y
FROM (
(SELECT pkid, x, y FROM foo LIMIT 0) -- parenthesis needed with LIMIT
UNION ALL
VALUES
(1, 20, NULL) -- no type casts here
, (2, 50, NULL)
) t -- column names and types are already defined
WHERE f.pkid = t.pkid;
サブクエリの最初のサブ選択:
(SELECT x, y, pkid FROM foo LIMIT 0)
列の名前とタイプを取得しますが、LIMIT 0
実際の行を追加できないようにします。後続の行は、現在明確に定義されている行タイプに強制変換され、タイプと一致するかどうかをすぐにチェックします。元のフォームよりも微妙に改善されているはずです。
すべての値を提供している間 表の列この短い構文は、最初の行に使用できます:
(TABLE foo LIMIT 0)
主要な制限 :Postgresは、独立したVALUES
の入力リテラルをキャストします すぐに「ベストエフォート」タイプへの表現。後で最初のSELECT
の指定されたタイプにキャストしようとしたとき 、想定されるタイプとターゲットタイプの間に登録された割り当てキャストがない場合、一部のタイプではすでに手遅れになっている可能性があります。例:text
->timestamp
またはtext
-> json
。
プロ:
- 最小限のオーバーヘッド。
- 読みやすく、シンプルで高速です。
- 必要なのは、テーブルの関連する列名だけです。
短所:
- タイプによってはタイプの解決に失敗する場合があります。
1。 LIMIT 0
の行を選択します 、UNION ALL SELECT
で行を追加します
UPDATE foo f
SET x = t.x
, y = t.y
FROM (
(SELECT pkid, x, y FROM foo LIMIT 0) -- parenthesis needed with LIMIT
UNION ALL SELECT 1, 20, NULL
UNION ALL SELECT 2, 50, NULL
) t -- column names and types are already defined
WHERE f.pkid = t.pkid;
プロ:
- 0のように。 、ただし、タイプ解決の失敗を回避します。
短所:
-
UNION ALL SELECT
VALUES
より遅い テストで見つけたように、行の長いリストの式。 - 行ごとの詳細な構文。
2。 VALUES
列ごとのタイプの式
...
FROM (
VALUES
((SELECT pkid FROM foo LIMIT 0)
, (SELECT x FROM foo LIMIT 0)
, (SELECT y FROM foo LIMIT 0)) -- get type for each col individually
, (1, 20, NULL)
, (2, 50, NULL)
) t (pkid, x, y) -- columns names not defined yet, only types.
...
0。とは異なります これにより、タイプの早期解決が回避されます。
VALUES
の最初の行 式はNULL
の行です 後続のすべての行のタイプを定義する値。この主要なノイズ行は、WHERE f.pkid = t.pkid
によってフィルタリングされます。 後で、それは日の目を見ることはありません。他の目的では、OFFSET 1
を使用して追加された最初の行を削除できます サブクエリで。
プロ:
- 通常、1よりも高速です。 (または0。 )
- 列が多く、関連する列が少ないテーブルの短い構文。
- 必要なのは、テーブルの関連する列名だけです。
短所:
- 数行のみの詳細な構文
- 読みにくい(IMO)。
3。 VALUES
行タイプの式
UPDATE foo f
SET x = (t.r).x -- parenthesis needed to make syntax unambiguous
, y = (t.r).y
FROM (
VALUES
('(1,20,)'::foo) -- columns need to be in default order of table
,('(2,50,)') -- nothing after the last comma for NULL
) t (r) -- column name for row type
WHERE f.pkid = (t.r).pkid;
あなたは明らかにテーブル名を知っています。列の数とその順序もわかっている場合は、これを使用できます。
PostgreSQLのすべてのテーブルに対して、行タイプが自動的に登録されます。式の列数と一致する場合は、テーブルの行タイプ('(1,50,)'::foo
)にキャストできます。 )これにより、列タイプを暗黙的に割り当てます。 NULL
を入力するには、カンマの後ろに何も入れないでください 価値。無関係な末尾の列ごとにコンマを追加します。
次の手順では、示されている構文を使用して個々の列にアクセスできます。 フィールド選択の詳細 マニュアルで。
または、追加することもできます NULL値の行で、実際のデータに統一された構文を使用します:
...
VALUES
((NULL::foo)) -- row of NULL values
, ('(1,20,)') -- uniform ROW value syntax for all
, ('(2,50,)')
...
プロ:
- 最速(少なくとも行と列が少ない私のテストでは)
- すべての列が必要ないくつかの行またはテーブルの最短構文。
- テーブルの列を詳しく説明する必要はありません。すべての列に自動的に一致する名前が付けられます。
短所:
- レコード/行/複合型からのフィールド選択の構文はあまり知られていません。
- デフォルトの順序で関連する列の数と位置を知る必要があります。
4。 VALUES
分解による表現 行タイプ
3。のように 、ただし、標準構文では分解された行を使用します:
UPDATE foo f
SET x = t.x
, y = t.y
FROM (
VALUES
(('(1,20,)'::foo).*) -- decomposed row of values
, (2, 50, NULL)
) t(pkid, x, y) -- arbitrary column names (I made them match)
WHERE f.pkid = t.pkid; -- eliminates 1st row with NULL values
または、NULL値の先頭行を再度使用します:
...
VALUES
((NULL::foo).*) -- row of NULL values
, (1, 20, NULL) -- uniform syntax for all
, (2, 50, NULL)
...
長所と短所 3。のように 、ただし、より一般的に知られている構文を使用します。
そして、列名を(必要に応じて)綴る必要があります。
5。 VALUES
行タイプからフェッチされたタイプの式
Unrilがコメントしたように、2。の長所を組み合わせることができます。 および4。 列のサブセットのみを提供するには:
UPDATE foo f
SET ( x, y)
= (t.x, t.y) -- short notation, see below
FROM (
VALUES
((NULL::foo).pkid, (NULL::foo).x, (NULL::foo).y) -- subset of columns
, (1, 20, NULL)
, (2, 50, NULL)
) t(pkid, x, y) -- arbitrary column names (I made them match)
WHERE f.pkid = t.pkid;
長所と短所 4。のように 、ただし、列の任意のサブセットを操作でき、完全なリストを知る必要はありません。
UPDATE
の短い構文も表示します それ自体は、列が多い場合に便利です。関連:
- すべての列の一括更新
4。と5.が私のお気に入りです。
db<>ここでフィドル -すべてを示す