PostgreSQL & # 8220; IF & # 8221; Errore di sintassi
-
03-07-2019 - |
Domanda
Sono nuovo con PostgreSQL e ho già il mio primo problema ..
Ho scritto del codice per capire come funzionano le transazioni, seguendo il manuale passo passo.
Per farla breve, ho creato 2 tabelle, utente e movimenti: nel primo ci sono le colonne nome, e-mail e credito, nel secondo le colonne da, a, import.
Quindi, stavo provando in questo modo:
BEGIN;
INSERT INTO movements (from, to, import) VALUES ('mary', 'steve', 600);
UPDATE users SET credit = credit - 600 WHERE name = 'mary';
UPDATE users SET credit = credit + 600 WHERE name = 'steve';
--here comes the problem!
IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
ROLLBACK;
END IF
COMMIT;
Ottengo sempre l'errore:
ERRORE: errore di sintassi pari o vicino a " IF "
Dove mi sbaglio?
P.S .: Non concentrarti sulla funzionalità di esempio, è solo una prova per me capire le transazioni .. e ora, la clausola IF ...
Soluzione
Come già dice Johannes: stai mescolando SQL normale con PL / pgSQL, il linguaggio delle procedure memorizzate. Il collegamento fornito da Johannes dovrebbe spiegarti il ??concetto di stored procedure.
Suppongo che lo stai facendo come una sceneggiatura? Eseguire una frase dopo l'altra? Temo che tu possa fare solo quello che vuoi fare all'interno di una Stored Procedure, o Funzione, come potresti chiamarla. Questo perché quando si eseguono affermazioni in questo modo, ogni affermazione è autonoma senza alcuna relazione o informazione relativa alle altre affermazioni.
Inoltre puoi consultare il seguente link per maggiori informazioni su come usare IF ... THEN ... ELSE ... END IF; condizioni all'interno di plpgsql: link .
Modifica
Non so se ROLLBACK è autorizzato a quel punto (perché ogni procedura memorizzata è già nella propria transazione), ma devi essere in grado di capirlo da solo utilizzando la documentazione estesa @ http://www.postgresql.org . Ecco una funzione di esempio con il tuo codice, dimostrando anche qualche altra sintassi:
CREATE OR REPLACE FUNCTION public.test()
RETURNS integer AS
$
DECLARE
tempvar integer;
BEGIN
tempvar := 1;
INSERT INTO movements (from, to, import) VALUES ('mary', 'steve', 600);
UPDATE users SET credit = credit - 600 WHERE name = 'mary';
UPDATE users SET credit = credit + 600 WHERE name = 'steve';
--here comes the problem!
IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
ROLLBACK;
END IF;
RETURN tempvar;
END
$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER;
Tuttavia, se stai davvero seguendo questa strada, ti consiglio di utilizzare un gestore DB GUI. È più facile imparare tutto questo.
Altri suggerimenti
Sembra che tu usi il semplice SQL
ma l'istruzione IF
fa parte dell' PL / pgSQL
linguaggio procedurale che fa parte di PostgreSQL.
Puoi provare a modificare la parte IF, da:
IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
ROLLBACK;
END IF
a
SELECT SUM(credit) INTO v_credit FROM users WHERE name = 'mary';
IF (v_credit) < 0 THEN
ROLLBACK;
END IF
Supponendo che v_credit sia una variabile definita in precedenza. IMHO, Postgre presume che la query SELECT restituisca più di un risultato, anche se sei certo che sia unico. Quindi penso che potresti provare ad assegnare il valore a una variabile prima.
Se vuoi evitare la possibilità di riscrivere il tuo codice come:
BEGIN;
INSERT INTO movements (from, to, import)
SELECT 'mary', 'steve', CASE credit < 600 WHEN TRUE THEN 0 ELSE 600 END;
UPDATE users SET credit = credit - CASE credit < 600 WHEN TRUE THEN 0 ELSE 600 END
WHERE name = 'mary';
UPDATE users u SET u.credit = u.credit + CASE v.credit < 600 WHEN TRUE THEN 0 ELSE 600 END
FROM users v
WHERE u.name = 'steve' and v.name = 'mary'
COMMIT;
Sì, questo è stupido :).
Simile a Microsoft SQL e T / SQL, dovresti essere in grado di mescolare SQL normale con PL / pgSQL se sono nella sequenza corretta. Ecco un esempio in cui la sequenza è importante in un proc memorizzato SQL / PL misto:
Non è possibile racchiudere le istruzioni condizionali all'interno del cursore: è necessario posizionare il cursore all'interno dell'istruzione condizionale. Se esegui la sequenza al contrario, otterrai lo stesso errore che avevi visto, "ERRORE: errore di sintassi pari o vicino a " IF "":
CREATE OR REPLACE FUNCTION getSubsystemFaultListCount(_bunoid integer, _subsystem text, _starttime timestamp without time zone, _stoptime timestamp without time zone)
RETURNS refcursor AS
$BODY$
DECLARE mycurs refcursor;
BEGIN
IF _subsystem = 'ALL' THEN
OPEN mycurs FOR
SELECT count(*), fs_fault.faultcode, fs_fault.downloadtime
FROM fs_fault
WHERE fs_fault.bunoid = _bunoid
AND fs_fault.statusid IN(2, 4)
AND fs_fault.downloadtime BETWEEN _starttime AND _stoptime
GROUP BY fs_fault.faultcode, fs_fault.downloadtime;
RETURN mycurs;
ELSE
OPEN mycurs FOR
SELECT count(*), fs_fault.faultcode, fs_fault.downloadtime
FROM fs_fault
WHERE fs_fault.bunoid = _bunoid
AND fs_fault.subsystemid
IN(SELECT id FROM fs_subsystem WHERE type = _subsystem)
AND fs_fault.statusid IN(2, 4)
AND fs_fault.downloadtime BETWEEN _starttime AND _stoptime
GROUP BY fs_fault.faultcode, fs_fault.downloadtime;
RETURN mycurs;
END IF;
END;
$BODY$
Sono un principiante in PostGresSQL; questa funzione è solo un esempio.