Noizean behin, garatzaileak behar du parametro multzo bat edo baita hautaketa oso bat ere pasa eskaerari "sarreran". Batzuetan arazo honi irtenbide oso bitxiak daude.
Goazen “kontrakotik” eta ikus dezagun nola ez, zergatik eta nola egin dezakezun hobeto.
Eskaeraren gorputzean balioak "txertatzea" zuzena
Normalean honelako itxura du:
query = "SELECT * FROM tbl WHERE id = " + value
... edo honela:
query = "SELECT * FROM tbl WHERE id = :param".format(param=value)
Metodo honi buruz esaten da, idatzi eta
Ia beti da SQL injekziorako zuzeneko bidea eta karga gehigarria negozio-logikan, zure kontsulta-katea "itsastera" behartuta dagoena.
Planteamendu hori partzialki justifika daiteke behar izanez gero. partizioa erabili PostgreSQL 10. bertsioetan eta ondorengoetan, plan eraginkorragoa izateko. Bertsio hauetan, eskaneatutako atalen zerrenda transmititutako parametroak kontuan hartu gabe zehazten da, eskaeraren gorputzaren arabera soilik.
$n argumentu
Erabili
Argudio kopuru aldakorra
Arazoak itxarongo zaizkigu aldez aurretik argumentu kopuru ezezaguna pasa nahi dugunean:
... id IN ($1, $2, $3, ...) -- $1 : 2, $2 : 3, $3 : 5, ...
Eskaera formulario honetan uzten baduzu, balizko injekzioetatik salbatuko gaituen arren, eskaera itsatsi / analizatu beharra ekarriko du. aukera bakoitzerako argumentu kopurutik. Dagoeneko aldi bakoitzean egitea baino hobea da, baina gabe egin dezakezu.
Nahikoa da parametro bakarra pasatzea array baten irudikapen serializatua:
... id = ANY($1::integer[]) -- $1 : '{2,3,5,8,13}'
Desberdintasun bakarra argumentua nahi den matrize motara esplizituki bihurtzeko beharra da. Baina horrek ez du arazorik sortzen, aldez aurretik badakigu eta nora zuzentzen garen.
Lagin-transferentzia (matrizea)
Normalean hauek dira datu-multzoak transferitzeko "eskaera bakarrean" datu-basean txertatzeko aukera guztiak:
INSERT INTO tbl(k, v) VALUES($1,$2),($3,$4),...
Eskaeraren "berriro itsatsiarekin" deskribatutako arazoez gain, honek ere eraman gaitzake oroimenik gabe eta zerbitzariaren kraskatzea. Arrazoia sinplea da - PG-k memoria gehigarria gordetzen du argumentuetarako, eta multzoko erregistro-kopurua Wishlist negozio-logikako aplikazioak soilik mugatzen du. Batez ere kasu klinikoetan ikusi beharra zegoen $ 9000 baino handiagoak diren "zenbakitutako" argumentuak - Ez egin horrela.
Berridatzi dezagun kontsulta, dagoeneko aplikatuz "bi maila" serializazioa:
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;
Bai, array baten barruan balio "konplexuen" kasuan, komatxoekin markatu behar dira.
Argi dago modu honetan hautapena "zabaldu" dezakezula eremu kopuru arbitrario batekin.
desegin, ezetz,...
Noizean behin aipatu ditudan "array of arrays" baten ordez hainbat "array of columns" pasatzeko aukerak daude
SELECT
unnest($1::text[]) k
, unnest($2::integer[]) v;
Metodo honekin, zutabe ezberdinetarako balio-zerrendak sortzean akatsen bat egiten baduzu, oso erraza da guztiz lortzea. ustekabeko emaitzak, zerbitzariaren bertsioaren araberakoak ere:
-- $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
9.3 bertsiotik hasita, PostgreSQL-k json motarekin lan egiteko funtzio osoak ditu. Hori dela eta, zure sarrera-parametroak arakatzailean definituta badaude, bertan zuzenean eta formatu dezakezu json objektua SQL kontsultarako:
SELECT
key k
, value v
FROM
json_each($1::json); -- '{"a":1,"b":2,"c":3,"d":4}'
Aurreko bertsioetarako, metodo bera erabil daiteke bakoitza(hdenda), baina hstoreko objektu konplexuetatik ihes eginda "toleste" zuzenak arazoak sor ditzake.
json_populate_recordset
Aurrez badakizu "sarrera" json array-ko datuak taularen bat betetzera joango direla, asko aurrez dezakezu "deserreferentzian" eremuetan eta nahi dituzun motetara igortzen json_populate_recordset funtzioa erabiliz:
SELECT
*
FROM
json_populate_recordset(
NULL::pg_class
, $1::json -- $1 : '[{"relname":"pg_class","oid":1262},{"relname":"pg_namespace","oid":2615}]'
);
json_to_recordset
Eta funtzio honek pasatako objektuen array hautapen batean "zabalduko" du, taula formatuan fidatu gabe:
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
BEHIN BATEKO MAHAIA
Baina transmititutako laginaren datu-kopurua oso handia bada, serieko parametro batera botatzea zaila da, eta batzuetan ezinezkoa da, behin-behineko bat behar baita. memoria esleipen handia. Esate baterako, kanpoko sistema batetik gertaeren datu sorta handi bat bildu behar duzu denbora luzez, eta, ondoren, datu-basearen aldean behin-behinean prozesatu nahi duzu.
Kasu honetan, irtenbiderik onena erabiltzea litzateke
CREATE TEMPORARY TABLE tbl(k text, v integer);
...
INSERT INTO tbl(k, v) VALUES($1, $2); -- повторить много-много раз
...
-- тут делаем что-то полезное со всей этой таблицей целиком
Metodoa ona da bolumen handien maiz ez transmititzeko datuak.
Bere datuen egitura deskribatzearen ikuspuntutik, aldi baterako taula bat "ohiko" taula batetik ezaugarri bakarrean desberdintzen da. pg_class sistemako taulaneta pg_type, pg_depend, pg_attribute, pg_attrdef, ... —eta ezer ez.
Hori dela eta, horietako bakoitzarentzat iraupen laburreko konexio ugari duten web sistemetan, halako taula batek sistema-erregistro berriak sortuko ditu aldi bakoitzean, datu-baserako konexioa ixtean ezabatzen direnak. Azkenean, TEMP TABLE kontrolatu gabe erabiltzeak pg_catalog-ko taulak "hantura" dakar eta erabiltzen dituzten eragiketa asko moteltzea.
Noski, horri aurre egin daiteke aldizkako pase HUTSEAN BETE sistemaren katalogo taulen arabera.
Saioko aldagaiak
Demagun aurreko kasuko datuen prozesamendua nahiko konplexua dela SQL kontsulta bakar baterako, baina sarritan egin nahi duzula. Hau da, prozedura prozedura erabili nahi dugu
Ezin dugu $n-parametrorik erabili bloke anonimo batera pasatzeko. Saioaren aldagaiak eta funtzioak egoeratik ateratzen lagunduko digu. uneko_ezarpena.
9.2 bertsioa baino lehen, aurrez konfiguratu behar zenuen
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
Onartutako beste hizkuntza prozesal batzuetan beste irtenbide batzuk daude eskuragarri.
Modu gehiago ezagutzen dituzu? Partekatu iruzkinetan!
Iturria: www.habr.com