web-dev-qa-db-ja.com

とにかく、複合タイプのレコード/行を持つ行の一連の列を更新する方法はありますか?

テーブルを取るfoo

CREATE TABLE foo(a,b,c,d)
AS VALUES
  (1,2,3,4);

行タイプでfooに挿入できます。

INSERT INTO foo
  SELECT (foo).*
  FROM foo;

INSERT INTO foo
  SELECT (v).*
  FROM ( VALUES (42,42,42,42) )
    AS v;

しかし、行タイプでfooを更新することはできません。

-- fails
UPDATE foo SET (a,b,c,d) = (
  SELECT ROW(1,2,3,4)
).*;

-- also fails.
UPDATE foo SET (a,b,c,d) = (SELECT (1,2,3,4));
ERROR:  number of columns does not match number of values
LINE 1: UPDATE foo SET (a,b,c,d) = (SELECT (1,2,3,4));

行全体を複合型で更新する構文はありますか?本当に奇妙なのは、これがNEWのトリガーで機能することです。トリガーなしで同じコードを記述しようとしています。

CREATE OR REPLACE FUNCTION foo()
RETURNS trigger
AS $$
  BEGIN
    NEW=(42,42,42,42);
    RETURN NEW;
  END;
$$ LANGUAGE plpgsql
IMMUTABLE;

CREATE TRIGGER ok
  BEFORE UPDATE ON foo
  FOR EACH ROW
  EXECUTE PROCEDURE foo();

-- The NEW row in trigger gets updated with (42,42,42,42)
-- the UPDATE succeeds; all rows (42,42,42,42)
UPDATE foo
  SET (a,b,c,d) = (1,2,3,4);

プロシージャ内の行オブジェクトを更新して、更新を変更できることがわかります。しかし、UPDATE ddlでそれを行うことはできませんか?同じ名前のテーブルで作成されたRECORDが同じように機能することを期待します。

-- Such as this,
UPDATE foo
  SET foo = (1,2,3,4);
4
Evan Carroll

これに関しては実際にたくさんの投稿があります。

ただし、 / u/pstefによると、これらのいずれかがコミットされ、この構文は現在機能しますHEAD 、@ ypercubeᵀᴹは9.6.5では機能しないと報告しています

UPDATE foo SET (a,b,c,d) = ROW(10,9,8,7);

ドキュメントはこれについてあまり言いません

標準によると、ターゲット列名の括弧で囲まれたサブリストのソース値は、正しい列数を生成する任意の行値式にすることができます。 ** PostgreSQLでは、ソース値を行コンストラクターまたはサブSELECTにすることのみが可能です。 **個々の列の更新された値は、行コンストラクタのケースではDEFAULTとして指定できますが、サブSELECT内では指定できません。

しかし、 PDATEの構文 でも確認できます。

   ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
1
Evan Carroll

どうですか(サーバー9.5.7)...

create table foo(a,b,c,d)
as values
  (1,2,3,4)
, (4,5,6,7)
, (8,9,0,null);

postgres=# select * from foo;
 a | b | c | d 
---+---+---+---
 1 | 2 | 3 | 4
 4 | 5 | 6 | 7
 8 | 9 | 0 |  
(3 rows)


update foo
set (a,b,c,d) = ( 
  select (v).*
  from ( values (42,42,42,42) ) as v 
) ;

postgres=# select * from foo;
 a  | b  | c  | d  
----+----+----+----
 42 | 42 | 42 | 42
 42 | 42 | 42 | 42
 42 | 42 | 42 | 42
(3 rows)

Dbfiddle ここ

または、実際に(トリガーなしで):

postgres=# update foo
postgres-# set (a,b,c,d) = (11,22,33,44) ;
UPDATE 3
postgres=# select * from foo;
 a  | b  | c  | d  
----+----+----+----
 11 | 22 | 33 | 44
 11 | 22 | 33 | 44
 11 | 22 | 33 | 44
(3 rows)
0
stefan

これは動作するようです(バージョン9.5および9.6)。問題が解決するかどうかはわかりません。

  • 行をfoo型に変換します。

    row(1,2,3,4)::foo
    
  • 列に展開します。

    select ( ).*
    

コード全体:

update foo set (a,b,c,d) = (select (row(1,2,3,4)::foo).*) ;
0
ypercubeᵀᴹ