2つの大きな問題があります:
1。 UPDATE
を置くことはできません サブクエリにまったく 。 data-modifyingで解決できます。 CTE
パトリックが示す
のように 、しかし、それは目前のケースに必要なものよりも高価で冗長です。
2。 潜在的に危険な名前の競合があります 、それはまだ対処されていません。
より良いクエリ/機能
SQL関数ラッパーは今のところ脇に置いておきます(これに戻ります)。簡単なUPDATE
を使用できます RETURNING
を使用 条項:
UPDATE tbl
SET value1 = 'something_new'
WHERE id = 123
RETURNING row_to_json(ROW(value1, value2));
RETURNING
句は、更新された行の列を含む任意の式を許可します。これは、データ変更CTEよりも短く安価です。
残りの問題:行コンストラクター ROW(...)
列名は保持されないため(これは既知の弱点です)、JSON値で汎用キーを取得します:
row_to_json
{"f1":"something_new","f2":"what ever is in value2"}
Postgres 9.3では、最初のステップをカプセル化するためのCTE別の関数、または明確に定義された行タイプへのキャストが必要になります。詳細:
Postgresでは9.4 <を使用するだけです。 code> json_build_object() またはjson_object()
:
UPDATE tbl
SET value1 = 'something_new'
WHERE id = 123
RETURNING json_build_object('value1', value1, 'value2', value2);
または:
...
RETURNING json_object('{value1, value2}', ARRAY[value1, value2]);
これで、元の列名またはキー名として選択したものを取得できます:
row_to_json
{"value1":"something_new","value2":"what ever is in value2"}
これを関数でラップするのは簡単です。これにより、2番目の問題が発生します...
名前の競合
元の関数では、関数パラメーターと列名に同じ名前を使用します。これは一般的に非常に悪い考えです 。どの識別子がどのスコープで最初に来るかをよく理解する必要があります。
手元の場合、結果はまったくナンセンスです:
Create Or Replace Function ExampleTable_Update (id bigint, value1 text) Returns
...
Update ExampleTable
Set Value1 = value1
Where id = id
Returning Value1, Value2;
...
$$ Language SQL;
id
の2番目のインスタンスを期待しているようですが 関数パラメータを参照しますが、参照しません。列名はSQLステートメントのスコープ内で最初に来て、2番目のインスタンスは列を参照します。その結果、常に true
の式になります id
のNULL値を除く 。したがって、すべての行を更新します。 、データの壊滅的な損失につながる可能性があります さらに悪いことに、SQL関数は 1つを返すため、後で理解することさえできないかもしれません。 RETURNING
で定義されている任意の行 関数の句( oneを返します 行のセットではなく、行)。
この特定のケースでは、 value1 =value1
もあるため、「ラッキー」になります。 、これは列を既存の値で上書きし、効果的に..非常に高価な方法で何もしません(トリガーが何かをしない限り)。 value1
が変更されていない任意の行を取得することに戸惑うかもしれません。 結果として。
だから、しないでください。
何をしているのかを正確に理解していない限り、このような潜在的な名前の競合は避けてください(明らかにそうではありません)。私が好きな規則の1つは、関数のパラメーター名と変数名の前にアンダースコアを付けることですが、列名はアンダースコアで始まることはありません。多くの場合、位置参照を使用して明確にすることができます: $ 1
、 $ 2
、...、しかしそれは問題の半分だけを回避します。 名前の競合を回避する限り、どの方法でも問題ありません。 。私が提案するもの:
CREATE OR REPLACE FUNCTION foo (_id bigint, _value1 text)
RETURNS json AS
$func$
UPDATE tbl
SET value1 = _value1
WHERE id = _id
RETURNING json_build_object('value1', value1, 'value2', value2);
$func$ LANGUAGE sql;
また、これは実際の列の値を返すことにも注意してください value1
で UPDATE
の後 、入力パラメータ _value1
と同じ場合と同じでない場合があります 。データベースルールまたはトリガーが干渉している可能性があります...