Saka wektu kanggo wektu pangembang perlu pass pesawat saka paramèter utawa malah kabeh pilihan kanggo request "ing lawang". Kadhangkala ana solusi sing aneh banget kanggo masalah iki.
Ayo dadi "saka ngelawan" lan ndeleng carane ora nindakake, apa, lan carane sampeyan bisa nindakake iku luwih apik.
Langsung "sisipan" nilai ing awak panyuwunan
Biasane katon kaya iki:
query = "SELECT * FROM tbl WHERE id = " + value
... utawa kaya iki:
query = "SELECT * FROM tbl WHERE id = :param".format(param=value)
About cara iki ngandika, ditulis lan
Meh mesthi path langsung kanggo injeksi SQL lan beban ekstra ing logika bisnis, sing dipeksa kanggo "lem" senar pitakon sampeyan.
Pendekatan iki bisa ditrapake sebagian mung yen perlu. nggunakake partisi ing PostgreSQL versi 10 lan ngisor kanggo rencana sing luwih efisien. Ing versi kasebut, dhaptar bagean sing dipindai ditemtokake tanpa njupuk parameter sing dikirim, mung adhedhasar badan panyuwunan.
$n argumen
Gunakake
Nomer variabel argumen
Masalah bakal nunggu kita nalika kita pengin ngliwati nomer argumen sing ora dingerteni sadurunge:
... id IN ($1, $2, $3, ...) -- $1 : 2, $2 : 3, $3 : 5, ...
Yen sampeyan ninggalake panjaluk kasebut ing formulir iki, mula sanajan bakal nylametake kita saka injeksi potensial, nanging isih mbutuhake lem / ngurai panyuwunan kasebut. kanggo saben pilihan saka jumlah argumen. Wis luwih apik tinimbang nindakake saben wektu, nanging sampeyan bisa nindakake tanpa.
Iku cukup kanggo pass mung siji parameter ngemot perwakilan serial saka larik:
... id = ANY($1::integer[]) -- $1 : '{2,3,5,8,13}'
Bentenipun mung kudu ngonversi argumentasi kanthi jelas menyang jinis array sing dikarepake. Nanging iki ora nyebabake masalah, amarga kita wis ngerti luwih dhisik ing ngendi kita bakal ditangani.
Transfer sampel (matriks)
Biasane iki kabeh pilihan kanggo nransfer set data kanggo dilebokake menyang database "ing siji panyuwunan":
INSERT INTO tbl(k, v) VALUES($1,$2),($3,$4),...
Saliyane masalah kasebut ing ndhuwur karo "re-gluing" panjalukan, iki uga bisa mimpin kita kanggo kebak memorine lan kacilakan server. Alesané prasaja - PG cadangan memori tambahan kanggo bantahan, lan nomer cathetan ing pesawat diwatesi mung dening Wishlist aplikasi logika bisnis. Ing kasus utamané Clinical iku perlu kanggo ndeleng argumen "nomer" luwih saka $9000 - aja nglakoni cara iki.
Ayo nulis maneh pitakon, wis nglamar serialisasi "loro-tingkat".:
INSERT INTO tbl
SELECT
unnest[1]::text k
, unnest[2]::integer v
FROM (
SELECT
unnest($1::text[])::text[] -- $1 : '{"{a,1}","{b,2}","{c,3}","{d,4}"}'
) T;
Ya, ing kasus nilai "kompleks" ing array, kudu dibingkai nganggo kuotasi.
Cetha yen kanthi cara iki sampeyan bisa "ngembangake" pilihan kanthi jumlah lapangan sing sewenang-wenang.
unnest, unnest,…
Saka wektu kanggo wektu ana opsi kanggo pass tinimbang "array of arrays" sawetara "arrays of columns" sing dakkandhakake
SELECT
unnest($1::text[]) k
, unnest($2::integer[]) v;
Kanthi metode iki, yen sampeyan salah nalika nggawe dhaptar nilai kanggo kolom sing beda-beda, gampang banget kanggo ngrampungake. asil sing ora dikarepke, sing uga gumantung ing versi server:
-- $1 : '{a,b,c}', $2 : '{1,2}'
-- PostgreSQL 9.4
k | v
-----
a | 1
b | 2
c | 1
a | 2
b | 1
c | 2
-- PostgreSQL 11
k | v
-----
a | 1
b | 2
c |
JSON
Miwiti saka versi 9.3, PostgreSQL nduweni fungsi lengkap kanggo nggarap jinis json. Mulane, yen paramèter input ditetepake ing browser, sampeyan bisa langsung lan mbentuk obyek json kanggo query SQL:
SELECT
key k
, value v
FROM
json_each($1::json); -- '{"a":1,"b":2,"c":3,"d":4}'
Kanggo versi sadurungé, cara sing padha bisa digunakake kanggo saben (hstore), nanging bener "lempitan" karo uwal obyek Komplek ing hstore bisa nimbulaké masalah.
json_populate_recordset
Yen sampeyan ngerti sadurunge yen data saka "input" array json bakal ngisi sawetara tabel, sampeyan bisa nyimpen akeh ing kolom "dereferencing" lan casting menyang jinis sing dikarepake nggunakake fungsi json_populate_recordset:
SELECT
*
FROM
json_populate_recordset(
NULL::pg_class
, $1::json -- $1 : '[{"relname":"pg_class","oid":1262},{"relname":"pg_namespace","oid":2615}]'
);
json_to_recordset
Lan fungsi iki mung bakal "ngembangake" macem-macem obyek menyang pilihan, tanpa gumantung ing format tabel:
SELECT
*
FROM
json_to_recordset($1::json) T(k text, v integer);
-- $1 : '[{"k":"a","v":1},{"k":"b","v":2}]'
k | v
-----
a | 1
b | 2
TABEL SEMENTARA
Nanging yen jumlah data ing sampel sing ditularaké gedhe banget, banjur uncalan menyang siji parameter serialized angel, lan kadhangkala mokal, amarga iku mbutuhake siji-wektu. alokasi memori gedhe. Contone, sampeyan kudu ngumpulake kumpulan gedhe saka data acara saka sistem external kanggo dangu, lan banjur pengin proses siji-wektu ing sisih database.
Ing kasus iki, solusi sing paling apik bakal digunakake
CREATE TEMPORARY TABLE tbl(k text, v integer);
...
INSERT INTO tbl(k, v) VALUES($1, $2); -- повторить много-много раз
...
-- тут делаем что-то полезное со всей этой таблицей целиком
Cara kasebut apik kanggo transmisi arang volume gedhe data.
Saka sudut pandang njlèntrèhaké struktur data, tabel sauntara beda karo tabel "biasa" mung ing siji fitur. ing tabel sistem pg_class, lan ing pg_type, pg_depend, pg_attribute, pg_attrdef, ... - lan ora ana apa-apa.
Mulane, ing sistem web kanthi jumlah sambungan sing cendhak kanggo saben wong, tabel kasebut bakal ngasilake cathetan sistem anyar saben wektu, sing bakal dibusak nalika sambungan menyang database ditutup. Pungkasane, nggunakake uncontrolled TEMP TABLE ndadékaké kanggo "abuh" saka tabel ing pg_catalog lan kalem akeh operasi sing digunakake.
Mesthi, iki bisa dilawan pass periodik VACUUM FULL miturut tabel katalog sistem.
Variabel Sesi
Upaminipun ngolah data saka kasus sadurunge cukup rumit kanggo query SQL siji, nanging sampeyan pengin nindakake cukup kerep. Yaiku, kita pengin nggunakake pangolahan prosedural ing
Kita uga ora bisa nggunakake $n-parameter kanggo pass menyang pemblokiran anonim. Variabel sesi lan fungsi bakal mbantu kita metu saka kahanan kasebut. saiki_setting.
Sadurunge versi 9.2, sampeyan kudu pra-konfigurasi
SET my.val = '{1,2,3}';
DO $$
DECLARE
id integer;
BEGIN
FOR id IN (SELECT unnest(current_setting('my.val')::integer[])) LOOP
RAISE NOTICE 'id : %', id;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- NOTICE: id : 1
-- NOTICE: id : 2
-- NOTICE: id : 3
Ana solusi liyane sing kasedhiya ing basa prosedural liyane sing didhukung.
Ngerti cara liyane? Nuduhake ing komentar!
Source: www.habr.com