Aș dori să fac cast de la ARGV[] care este text la int array în PostgreSQL unde am marcat pseudocodul prin TODO în cod. Codul în PostgreSQL 9.4.3 pe x86_64-unknown-linux-gnu, compilat de gcc (Debian 4.9.2-10) 4.9.2, 64 de biți:
CREATE TABLE measurements (
measurement_id SERIAL PRIMARY KEY NOT NULL,
measurement_size_in_bytes INTEGER NOT NULL
);
CREATE TABLE events (
event_id SERIAL PRIMARY KEY NOT NULL,
measurement_id INTEGER NOT NULL,
event_index_start INTEGER NOT NULL,
event_index_end INTEGER NOT NULL
);
CREATE OR REPLACE FUNCTION insaft_function()
RETURNS TRIGGER AS
$func$
BEGIN
-- TODO Loop until TG_ARGV[0] empty
INSERT INTO events (measurement_id, event_index_start, event_index_end)
SELECT NEW.measurement_id, TG_ARGV[0]::int[], TG_ARGV[1]::int[];
-- END TODO
RETURN NULL; -- result ignored since this is an AFTER trigger
END
$func$ LANGUAGE plpgsql;
CREATE TRIGGER insaft_measurement_ids
AFTER INSERT ON measurements
FOR EACH ROW EXECUTE PROCEDURE insaft_function("{101, 111, 121}", "{101, 111, 121}");
pe care îl pot începe prin
INSERT INTO measurements (measurement_size_in_bytes) VALUES (888);
Știu că greșeala este în turnarea de aici TG_ARGV[0]::int[]
în intarray prin care aș vrea să fac o buclă până când intarray-ul este gol. Este posibil să existe o modalitate mai bună de a face astfel de inserții în buclă.
Rezultatul codului lui ErwinBrandstetter
Cod
DROP TABLE IF EXISTS measurements, events, file_headers;
CREATE TABLE measurements (
measurement_id SERIAL PRIMARY KEY NOT NULL,
measurement_size_in_bytes INTEGER NOT NULL
);
CREATE TABLE events (
event_id SERIAL PRIMARY KEY NOT NULL,
measurement_id INTEGER NOT NULL,
event_index_start INTEGER NOT NULL,
event_index_end INTEGER NOT NULL
);
DROP TRIGGER IF EXISTS insaft_ids ON measurements;
DROP FUNCTION IF EXISTS insaft_function();
CREATE OR REPLACE FUNCTION insaft_function()
RETURNS TRIGGER AS
$func$
DECLARE
m int[];
BEGIN
FOREACH m SLICE 1 IN ARRAY TG_ARGV::int[]
LOOP
INSERT INTO events (measurement_id, event_index_start, event_index_end)
SELECT NEW.measurement_id, m[1], m[2]; -- Postgres array starts with 1 !
END LOOP;
RETURN NULL; -- result ignored since this is an AFTER trigger
END
$func$ LANGUAGE plpgsql;
CREATE TRIGGER insaft_ids
AFTER INSERT ON measurements
FOR EACH ROW EXECUTE PROCEDURE insaft_function('{{101,201},{201,300}}');
Rulează
sudo -u postgres psql detector -c "INSERT INTO measurements (measurement_size_in_bytes) VALUES (77777);"
obține
ERROR: invalid input syntax for integer: "{{101,201},{201,300}}"
CONTEXT: PL/pgSQL function insaft_function() line 5 at FOREACH over array
Cum se poate face cast de la ARGV[] care este text la int array în PostgreSQL?
În timp ce treceți numere întregi, , puteți fie să distribuiți întregul array:
TG_ARGV::int[]
fie puteți arunca un element, , atunci acesta trebuie să fie tipul elementului:
TG_ARGV[0]::int
Am folosit acest mod în răspunsul meu la întrebarea anterioară:
- SELECT în funcția de declanșare în două tabele
Cu toate acestea,, , nu treceți numere întregi, ci reprezentarea textuală a tablourilor de numere întregi: un literal de tablou de numere întregi – cu o sintaxă ilegală, de asemenea: valorile trebuie să fie incluse în ghilimele simple, , ghilimelele duble sunt pentru identificatori:
<strike>FOR EACH ROW EXECUTE PROCEDURE insaft_function("{101, 111, 121}", "{101, 111, 121}"); </strike>
FOR EACH ROW EXECUTE PROCEDURE insaft_function('{101, 111, 121}', '{101, 111, 121}');
Din moment ce nu treceți integer
ci literale de matrice de numere întregi, nu puteți face niciuna dintre acestea în codul dumneavoastră. Luați în considerare (folosind un exemplu mai clar cu numere distincte):
SELECT (ARRAY['{101, 111, 121}', '{201, 211, 221}'])[1]::int[];
SELECT (ARRAY['{101, 111, 121}', '{201, 211, 221}'])::text[];
SELECT (ARRAY['{101, 111, 121}'::int[], '{201, 211, 221}'])::int[];
SELECT (ARRAY['{101, 111, 121}'::int[], '{201, 211, 221}'])[1][1];
SELECT (ARRAY['{{101, 111, 121},{201, 211, 221}}'])[1];
SELECT (ARRAY['{{101, 111, 121},{201, 211, 221}}'])[1]::int[];
@Chris a furnizat mai multe pentru asta.
Soluția pentru funcția dvs.
Vă sugerez fie treceți toate numerele întregi fie un literal de matrice bidimensională. Cod demonstrativ pentru acesta din urmă:
'{{101,111,121},{201,211,221}}'
Sau mai degrabă (array-ul pivotat, pe baza presupunerilor mele):
'{{101,201},{111,211},{121,221}}'
Deci, aceasta este unul parametru:
CREATE TRIGGER ...
FOR EACH ROW EXECUTE PROCEDURE insaft_function('{{101,201},{111,211},{121,221}}');
În ceea ce privește bucla, folosiți FOREACH m SLICE 1 IN ARRAY
:
- Postgres – matrice pentru buclă
Funcția ar putea arăta astfel:
CREATE OR REPLACE FUNCTION insaft_function()
RETURNS TRIGGER AS
$func$
DECLARE
m int[];
BEGIN
FOREACH m SLICE 1 IN ARRAY TG_ARGV[0]::int[] -- reference 1st param
LOOP
INSERT INTO events (measurement_id, event_index_start, event_index_end)
SELECT NEW.measurement_id, m[1], m[2]; -- Postgres array starts with 1 !
END LOOP;
RETURN NULL; -- result ignored since this is an AFTER trigger
END
$func$ LANGUAGE plpgsql;
Dar am bănuielile mele că ar putea exista o abordare generală mai simplă. Acest lucru are sens doar dacă aveți mai multe tabele care au nevoie de un declanșator similar, dar cu numere întregi diferite …
Mie mi se pare că ești pe drumul cel bun, dacă înțeleg clar întrebarea ta (ceea ce nu sunt sigur că sunt. 😛 )
Pentru mine, se pare că ai nevoie pur și simplu de un DECLARE
bloc, în care să declarați valori variabile care vor persista pe tot parcursul blocului de funcții.
Adăugați DECLARE
CREATE OR REPLACE FUNCTION insaft_function()
RETURNS TRIGGER AS
DECLARE
myarray_0 int[] := TG_ARGV[0]::int[]
myarray_1 int[] := TG_ARGV[1]::int[]
$func$
BEGIN
-- TODO Loop until myarray_0 empty
-- Decide what you really want to do here!!
-- Is it a parallel loop through myarray_0 and myarray_1, or a Cartesian, or...
-- END TODO
RETURN NULL; -- result ignored since this is an AFTER trigger
END
$func$ LANGUAGE plpgsql;
Ai făcut distribuția corect, dar dacă vrei să le treci în buclă cu ușurință în funcție, trebuie doar să o faci în avans cu un bloc DECLARE
bloc.
Putem lăsa dezbaterea pentru altă dată, însă, dacă aceasta este cea mai bună abordare pentru realizarea inserțiilor pe care sperați să le faceți…
int
denotă tipul de număr întreg șiint[]
denotă un array de numere întregi? Câteva noțiuni de bază aici: stackoverflow.com/a/1241414884/939860. > Por Erwin Brandstetter.TG_ARGV
[0]
::int[]
. Am testat două versiuni (either pass all integer numbers or a 2-dimensional array literal
) și am amestecat declanșatorul și definiția funcției din ambele din greșeală. SintaxaTG_ARGV::int[]
funcționează doar „toate numerele întregi” – mai multe parametri de genul:insaft_function(101,201,201,300)
. Din moment ce treceți un literal de text pentru o matrice int (2-dimensională) ca unul trebuie să vă referiți laTG_ARGV[0]
. Am adaptat codul de mai sus. – > Por Erwin Brandstetter.events.event_index_start
șievents.event_index_end
trebuie să fie definite cabigint
în consecință. – > Por Erwin Brandstetter.bigint
ifunsigned int
dar aicisigned int
deci păstrați pentru a folosi doarint
. Urmăriți thread-ul aici stackoverflow.com/questions/31533496/… – > Por Léo Léopold Hertz 준영.