Pergunta

Eu sou novo com o PostgreSQL, e eu já tenho o meu primeiro problema ..

Eu escrevi algum código para entender como funcionam transações, seguindo a etapa manual a passo.

Para ser breve, eu criei 2 tabelas, usuários e movimentos: no primeiro, há o nome, e-mail e de crédito colunas, nas segundas as colunas, para, importação

.

Então, eu estava tentando desta forma:

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;

Eu sempre recebo o erro:

ERRO: erro de sintaxe ou perto "IF"

Onde estou enganado?

P.S .: Não se concentrar no exemplo funcionalidade, é apenas um teste para mim entender as transações .. e agora, a cláusula if ...

Foi útil?

Solução

Como Johannes já diz: você está misturando SQL regular com PL / pgSQL, a linguagem de procedimentos armazenados. O link que Johannes fornece devem explicar o conceito de procedimentos armazenados para você.

Acho que você está fazendo isso como um script? Executando uma declaração após o outro? Eu tenho medo que você só pode fazer o que você quer fazer dentro de um procedimento armazenado ou função, como você pode chamá-lo. Isto porque, quando você está executando instruções desta forma, cada declaração está em seu próprio sem relação ou informações sobre as outras declarações.

Além disso, você pode olhar para o seguinte link para obter mais informações sobre como usar o IF ... THEN ... ELSE ... END IF; condicionais dentro plpgsql:. ?? ligação


EDIT:

Eu não sei se ROLLBACK é permitido naquele ponto (porque cada procedimento armazenado já está em sua própria transação), mas você deve ser capaz de descobrir isso por si mesmo usando a extensa documentação @ http://www.postgresql.org . Aqui está uma função de exemplo com o seu código nele, também demonstrando alguma outra sintaxe:

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;

No entanto, se você está realmente indo por este caminho, eu recomendo usar um gerenciador GUI DB. É mais fácil para aprender tudo isso.

Outras dicas

Você parece usar SQL simples, mas a declaração IF faz parte do PL/pgSQL linguagem procedural que faz parte do PostgreSQL.

Você poderia tentar modificar a parte IF, de:

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

para

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

Assumindo v_credit é uma variável que você definiu anteriormente. IMHO, Postgre assume retornos de consulta selecionar mais de um resultado, mesmo que você está muito certo de que ele é único. Então eu acho que você poderia tentar atribuir o valor a uma variável primeira antemão.

Se você quiser evitar a se você poderia reescrever seu 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;

Sim, esta é :) estúpido.

Semelhante ao SQL da Microsoft e T / SQL, você deve ser capaz de misturar SQL regular com PL / pgSQL se eles estão na sequência correcta. Aqui está um exemplo onde os assuntos de seqüência em um SQL / proc PL armazenados mista:

Você não pode envolver declarações condicionais dentro do cursor - você deve colocar o cursor dentro da instrução condicional. Se você fizer a seqüência o contrário, você obterá o mesmo erro que você tinha visto, 'ERRO: erro de sintaxe ou perto 'SE''

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$

Eu sou um novato no PostgresSQL; esta função é apenas um exemplo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top