Pregunta

Soy nuevo con PostgreSQL, y ya tengo mi primer problema ...

Escribí un código para comprender cómo funcionan las transacciones, siguiendo el manual paso a paso.

Para abreviar, he creado 2 tablas, usuario y movimientos: en la primera están las columnas de nombre, correo electrónico y crédito, en la segunda, las columnas de, a, importar.

Por lo tanto, estaba tratando de esta manera:

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;

Siempre me sale el error:

  

ERROR: error de sintaxis en o cerca de " IF "

¿Dónde estoy equivocado?

P.S .: No te centres en la funcionalidad de ejemplo, es solo una prueba para que entienda las transacciones ... y ahora, la cláusula IF ...

¿Fue útil?

Solución

Como Johannes ya dice: estás mezclando SQL regular con PL / pgSQL, el lenguaje del procedimiento almacenado. El enlace que Johannes proporciona debe explicarle el concepto de procedimientos almacenados.

Supongo que estás haciendo esto como un script? ¿Ejecutando una declaración tras otra? Me temo que solo puede hacer lo que quiera hacer dentro de un procedimiento almacenado o función, como podría llamarlo. Esto se debe a que cuando está ejecutando sentencias de esta manera, todas las afirmaciones son independientes y no tienen relación ni información con respecto a las otras afirmaciones.

Además, puede consultar el siguiente enlace para obtener más información sobre cómo usar IF ... THEN ... ELSE ... END IF; condicionales dentro de plpgsql: link .


EDIT:

No sé si ROLLBACK está permitido en ese momento (porque cada procedimiento almacenado ya está en su propia transacción), pero debe poder averiguarlo por sí mismo utilizando la extensa documentación @ http://www.postgresql.org . Aquí hay una función de ejemplo con su código, que también muestra alguna otra sintaxis:

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;

Sin embargo, si realmente vas por este camino, te recomiendo usar un administrador de base de datos GUI. Es más fácil aprender todo esto.

Otros consejos

Parece que usas SQL , pero la declaración IF es parte de PL / pgSQL lenguaje de procedimiento que forma parte de PostgreSQL.

Puedes intentar modificar la parte IF, de:

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

Suponiendo que v_credit es una variable que definió anteriormente. En mi humilde opinión, Postgre asume que la consulta SELECT devuelve más de un resultado, a pesar de que está muy seguro de que es único. Así que creo que podrías intentar asignar el valor a una variable de antemano.

Si desea evitarlo, puede volver a escribir su código como:

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í, esto es estúpido :).

Al igual que con SQL y T / SQL de Microsoft, debería poder mezclar SQL regular con PL / pgSQL si están en la secuencia correcta. Aquí hay un ejemplo donde la secuencia importa en un proceso almacenado de SQL / PL mixto:

No puede ajustar las sentencias condicionales dentro del cursor; debe colocar el cursor dentro de la sentencia condicional. Si haces la secuencia al revés, obtendrás el mismo error que habías visto, 'ERROR: error de sintaxis en " 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$

Soy un principiante en PostGresSQL; esta función es solo un ejemplo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top