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 ...

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top