PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

EXECUTE ... INTO ... USING câu lệnh trong PL / pgSQL không thể thực thi thành một bản ghi?

Thay thế đơn giản hơn cho câu trả lời đã đăng của bạn. Sẽ hoạt động tốt hơn nhiều.

Hàm này lấy một hàng từ một bảng nhất định ( in_table_name ) và giá trị khóa chính ( in_row_pk ), và chèn nó dưới dạng hàng mới vào cùng một bảng, với một số giá trị được thay thế ( in_override_values ​​ ). Giá trị khóa chính mới theo mặc định được trả về ( pk_new ).

CREATE OR REPLACE FUNCTION f_clone_row(in_table_name regclass
                                     , in_row_pk int
                                     , in_override_values hstore
                                     , OUT pk_new int) AS
$func$
DECLARE
   _pk   text;  -- name of PK column
   _cols text;  -- list of names of other columns
BEGIN

-- Get name of PK column
SELECT INTO _pk  a.attname
FROM   pg_catalog.pg_index     i
JOIN   pg_catalog.pg_attribute a ON a.attrelid = i.indrelid
                                AND a.attnum   = i.indkey[0]  -- 1 PK col!
WHERE  i.indrelid = 't'::regclass
AND    i.indisprimary;

-- Get list of columns excluding PK column
_cols := array_to_string(ARRAY(
      SELECT quote_ident(attname)
      FROM   pg_catalog.pg_attribute
      WHERE  attrelid = in_table_name -- regclass used as OID
      AND    attnum > 0               -- exclude system columns
      AND    attisdropped = FALSE     -- exclude dropped columns
      AND    attname <> _pk           -- exclude PK column
      ), ',');

-- INSERT cloned row with override values, returning new PK
EXECUTE format('
   INSERT INTO %1$I (%2$s)
   SELECT %2$s
   FROM  (SELECT (t #= $1).* FROM %1$I t WHERE %3$I = $2) x
   RETURNING %3$I'
 , in_table_name, _cols, _pk)
USING   in_override_values, in_row_pk -- use override values directly
INTO    pk_new;                       -- return new pk directly

END
$func$ LANGUAGE plpgsql;

Gọi:

SELECT f_clone_row('t', 1, '"col1"=>"foo_new","col2"=>"bar_new"'::hstore);

SQL Fiddle.

  • Sử dụng regclass là kiểu tham số đầu vào, vì vậy chỉ những tên bảng hợp lệ mới có thể được sử dụng để bắt đầu và việc chèn SQL bị loại trừ. Hàm cũng không thành công sớm hơn và duyên dáng hơn nếu bạn cung cấp tên bảng không hợp lệ.

  • Sử dụng OUT tham số ( pk_new ) để đơn giản hóa cú pháp.

  • Không cần phải tìm ra giá trị tiếp theo cho khóa chính theo cách thủ công. Nó được đưa vào tự động và trả lại sau khi thực tế. Điều đó không chỉ đơn giản hơn và nhanh hơn, bạn còn tránh được các số thứ tự bị lãng phí hoặc không theo thứ tự.

  • Sử dụng định dạng () để đơn giản hóa việc lắp ráp chuỗi truy vấn động và làm cho nó ít bị lỗi hơn. Lưu ý cách tôi sử dụng các tham số vị trí cho số nhận dạng và chuỗi tương ứng.

  • Tôi xây dựng dựa trên giả định ngầm của bạn các bảng được phép có một cột khóa chính duy nhất thuộc loại số nguyên với mặc định là cột . Điển hình là serial cột.

  • Yếu tố chính của hàm là INSERT cuối cùng :

    • Hợp nhất các giá trị ghi đè với hàng hiện có bằng cách sử dụng # = nhà điều hành trong một lựa chọn con và phân tách hàng kết quả ngay lập tức.
    • Sau đó, bạn chỉ có thể chọn các cột có liên quan trong SELECT chính .
    • Để Postgres chỉ định giá trị mặc định cho PK và lấy lại giá trị đó bằng RETURNING mệnh đề.
    • Ghi giá trị trả về vào OUT tham số trực tiếp.
    • Tất cả được thực hiện trong một lệnh SQL duy nhất, nói chung là nhanh nhất.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chuyển đổi Django từ SQLite sang PostgreSQL

  2. Đã xảy ra lỗi khi cài đặt pg (0.17.1) và Bundler không thể tiếp tục

  3. Sử dụng psql làm cách nào để liệt kê các tiện ích mở rộng được cài đặt trong cơ sở dữ liệu?

  4. Cột không tồn tại?

  5. Quyền bị từ chối đối với mối quan hệ