sql >> データベース >  >> RDS >> PostgreSQL

複数の行を更新するときにNULLタイプをキャストする

    スタンドアロンの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<>ここでフィドル -すべてを示す



    1. 式インデックスの検索

    2. 2つの日付の間の稼働日数を見つけるMySQL関数

    3. CMONHAを使用したClusterControlノードの高可用性構成

    4. Pythonのプロセス間でpostgresdbへの接続を共有する