スタンドアロン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;
プロ:
短所:
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よりも高速です。 )
- 多くの列があり、少数の列しかないテーブルの短い構文が関係します。
- テーブルの関連する列名を知っているだけで済みます。
短所:
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<>ここでフィドル-すべてを示します