Question Erreur de syntaxe PostgreSQL «IF»


Je suis nouveau avec PostgreSQL, et j'ai déjà mon premier problème.

J'ai écrit du code pour comprendre le fonctionnement des transactions, en suivant le manuel pas à pas.

Pour faire court, j'ai créé 2 tables, utilisateurs et mouvements: dans le premier, il y a les colonnes name, email et credit, dans la seconde les colonnes from, to, import.

Donc, j'essayais de cette façon:

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;

J'ai toujours l'erreur:

ERREUR: erreur de syntaxe à ou près de "IF"

Où est-ce que je me trompe?

P.S .: Ne vous concentrez pas sur la fonctionnalité exemple, c'est juste un essai pour comprendre les transactions .. et maintenant, la clause IF ...


11
2018-04-29 14:58


origine


Réponses:


Comme le dit déjà Johannes: vous mélangez du code SQL régulier avec PL / pgSQL, le langage de la procédure stockée. Le lien fourni par Johannes devrait vous expliquer le concept des procédures stockées.

Je suppose que vous le faites en tant que script? Exécuter une déclaration après l'autre? Je crains que vous ne puissiez faire ce que vous voulez faire dans une procédure stockée, ou une fonction, comme vous pouvez l’appeler. Cela est dû au fait que lorsque vous exécutez des instructions de cette manière, chaque déclaration est autonome, sans relation ni information concernant les autres déclarations.

De plus, vous pouvez consulter le lien suivant pour plus d'informations sur l'utilisation de IF ... THEN ... ELSE ... END IF; conditions dans plpgsql: lien.


MODIFIER:

Je ne sais pas si ROLLBACK est autorisé à ce stade (car chaque procédure stockée est déjà dans sa propre transaction), mais vous devez être capable de vous en rendre compte en utilisant la documentation complète @ http://www.postgresql.org. Voici un exemple de fonction avec votre code, montrant également une autre syntaxe:

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;

Cependant, si vous vous engagez vraiment dans cette voie, je vous recommande d’utiliser un gestionnaire de bases de données GUI. C'est plus facile d'apprendre tout cela.


6
2018-04-29 15:16



Vous semblez utiliser la plaine SQL mais le IF déclaration fait partie de la PL/pgSQL langage procédural faisant partie de PostgreSQL.


2
2018-04-29 15:02



Vous pouvez essayer de modifier la partie IF, à partir de:

IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
 ROLLBACK;
END IF

à

SELECT SUM(credit) INTO v_credit FROM users WHERE name = 'mary';
IF (v_credit) < 0 THEN
 ROLLBACK;
END IF

En supposant que v_credit est une variable que vous avez définie précédemment. IMHO, Postgre suppose que la requête SELECT renvoie plus d'un résultat, même si vous êtes absolument certain qu'il est unique. Donc, je pense que vous pourriez essayer d’attribuer la valeur à une variable en premier lieu.


1
2018-04-30 04:50



Si vous souhaitez éviter le si vous pouvez réécrire votre code en tant que:

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;

Oui, c'est stupide :).


1
2018-04-29 15:17



Semblable à SQL et T / SQL de Microsoft, vous devriez être capable de mélanger un SQL standard avec PL / pgSQL s'ils sont dans le bon ordre. Voici un exemple où la séquence est importante dans un processus stocké mixte SQL / PL:

Vous ne pouvez pas envelopper les instructions conditionnelles à l'intérieur du curseur - vous devez placer le curseur à l'intérieur de l'instruction conditionnelle. Si vous faites la séquence à l'envers, vous obtiendrez la même erreur que celle que vous avez vue, "ERROR: erreur de syntaxe à ou près de" 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$

Je suis débutant dans PostGresSQL; cette fonction n'est qu'un exemple.


0