簡體   English   中英

將對象的插值數組轉換為 postgresql 復合類型數組的正確方法是什么?

[英]What is the proper way of converting interpolated array of objects to a postgresql array of composite type?

我正在使用 SQL 函數執行多重插入,但因為它們不能接受記錄集作為 arguments 我必須先將它們轉換為數組。 它適用於基元數組,因為它們可以簡單地使用CAST (${value} as primitive_type[])進行轉換並完成。
然而,多插入查詢需要復合類型 arrays 並且它看起來不像CAST()與它們一起工作,因為它需要單列輸入。
所有查詢都顯示在這個小提琴上: https://dbfiddle.uk/w_Qbq-lw

表和類型

CREATE TABLE accounts (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
  login text NOT NULL,
  password text NOT NULL,
  email text
);

CREATE TYPE account_init AS (
  login text,
  password text,
  email text
);

職能

CREATE FUNCTION get_accounts(
  pagination_limit bigint DEFAULT 25,
  pagination_offset bigint DEFAULT 0,
  account_ids bigint[] DEFAULT NULL
)
RETURNS TABLE (
  id bigint,
  created_at timestamptz,
  login text,
  password text,
  email text
)
LANGUAGE SQL
AS $BODY$
  WITH input_accounts AS (
    SELECT
      id,
      created_at,
      login,
      password,
      email
    FROM
      accounts
    WHERE
      account_ids IS NULL OR id = ANY (account_ids)
    ORDER BY
      id
    LIMIT pagination_limit
    OFFSET pagination_offset
  )
  SELECT
    id,
    created_at,
    login,
    password,
    email
  FROM
    input_accounts
  ORDER BY
    id
$BODY$;

CREATE FUNCTION create_accounts(
  account_inits account_init[]
)
RETURNS TABLE (
  id bigint,
  created_at timestamptz,
  login text,
  password text,
  email text
)
LANGUAGE SQL
AS $BODY$
  WITH new_accounts AS (
    INSERT INTO accounts ( 
      login, 
      password, 
      email 
    )
    SELECT 
      login, 
      password, 
      email
    FROM 
      unnest(account_inits)
    RETURNING
      id
  )
  SELECT
    id,
    created_at,
    login,
    password,
    email
  FROM
    get_accounts(
      NULL,
      NULL,
      ARRAY(
        SELECT
          id
        FROM
          new_accounts
      )
    )
  ORDER BY
    id
$BODY$;

初始化數據

const account_inits = [
  {
    login:"EC4A42323F", 
    password: "3DF1542F23A29B73281EEC5EBB55FFE18C253A7E800E7A541B"
  },
  {
    login:"1D771C1E52", 
    password: "2817029563CC722FBC3D53F9F29F0000898F9843518D882E4A", 
    email: "a@b"
  },
  {
    login:"FB66381D3A", 
    password: "C8F865AC1D54CFFA56DEBDEEB671C8EF110991BBB3B9EE57D2", 
    email: null
  }
]

用法

--- insert data
WITH input_inits AS (
  SELECT
    login,
    password,
    email
  FROM
    json_to_recordset(${account_inits:json}) AS input_init(
      login text,
      password text,
      email text
    )
),
input_data AS (
  SELECT
    array_agg(
      CAST (
        (
          login,
          password,
          email
        ) AS account_init
      )
    ) AS account_inits
  FROM
    input_inits
)
SELECT
  new_accounts.id,
  new_accounts.created_at,
  new_accounts.login,
  new_accounts.password,
  new_accounts.email
FROM
  input_data
  CROSS JOIN
  create_accounts(input_data.account_inits) AS new_accounts
ORDER BY
  new_accounts.id ASC
;

目前我將它插入為:json ,然后將其轉換為 CTE 中的記錄集,然后在第二個 CTE 中將其轉換為復合類型數組,作為參數傳遞給 function。這似乎需要大量工作才能傳遞對象數組到 function arguments。我嘗試在沒有:json轉換的情況下工作,但遇到array[]相關或malformed object literal語法錯誤。

原來沒有。 “正確的”替代方案需要知道輸入數組中對象的預期鍵(以及所有嵌套對象/對象數組),以便構造正確的元組數組。
這基本上需要某種運行時引用模式,即使完美實現,仍然需要為每個新查詢文件編寫樣板代碼。 充其量它不會比helpers模塊中的函數或查詢中的json -> record set -> composite type array轉換更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM