Alternatif yang lebih sederhana untuk jawaban Anda yang diposting. Harus tampil jauh lebih baik.
Fungsi ini mengambil baris dari tabel yang diberikan (in_table_name
) dan nilai kunci utama (in_row_pk
), dan menyisipkannya sebagai baris baru ke dalam tabel yang sama, dengan beberapa nilai diganti (in_override_values
). Nilai kunci utama baru sesuai default dikembalikan (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;
Telepon:
SELECT f_clone_row('t', 1, '"col1"=>"foo_new","col2"=>"bar_new"'::hstore);
-
Gunakan
regclass
sebagai tipe parameter input, jadi hanya nama tabel yang valid yang dapat digunakan untuk memulai dan injeksi SQL dikesampingkan. Fungsi ini juga gagal lebih awal dan lebih lancar jika Anda harus memberikan nama tabel yang ilegal. -
Gunakan
OUT
parameter (pk_new
) untuk menyederhanakan sintaks. -
Tidak perlu mencari tahu nilai selanjutnya untuk kunci utama secara manual. Itu dimasukkan secara otomatis dan dikembalikan setelah fakta. Itu tidak hanya lebih sederhana dan lebih cepat, Anda juga menghindari nomor urut yang terbuang atau tidak berurutan.
-
Gunakan
format()
untuk menyederhanakan perakitan string kueri dinamis dan membuatnya kurang rawan kesalahan. Perhatikan bagaimana saya menggunakan parameter posisi untuk pengidentifikasi dan string masing-masing. -
Saya membangun asumsi implisit Anda bahwa tabel yang diizinkan memiliki satu kolom kunci utama bertipe integer dengan kolom default . Biasanya
serial
kolom. -
Elemen kunci dari fungsi ini adalah
INSERT
terakhir :- Gabungkan nilai penimpaan dengan baris yang ada menggunakan
#=
operator dalam subpilih dan segera dekomposisi baris yang dihasilkan. - Kemudian Anda hanya dapat memilih kolom yang relevan di
SELECT
utama . - Biarkan Postgres menetapkan nilai default untuk PK dan mendapatkannya kembali dengan
RETURNING
klausa. - Tuliskan nilai yang dikembalikan ke dalam
OUT
parameter secara langsung. - Semua dilakukan dalam satu perintah SQL, yang umumnya tercepat.
- Gabungkan nilai penimpaan dengan baris yang ada menggunakan