2009-04-29 3 views
11

Я новичок в PostgreSQL, и у меня уже есть первая проблема ..PostgreSQL «IF» синтаксическая ошибка

Я написал код, чтобы понять, как работают транзакции, после ручной шаг за шагом.

Чтобы сделать его коротким, я создал 2 таблицы, пользователя и движения: в первом есть имя, адрес электронной почты и столбцы кредита, во втором - столбцы from, to, import.

Итак, я пытался так:

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; 

Я всегда получаю ошибку:

ERROR: syntax error at or near "IF"

Где я ошибаюсь?

PS: Не сосредоточиться на примере функциональность, это просто испытание для меня, чтобы понять сделки .. и теперь, предложение IF ...

+0

Я добавил образец кода, по вашему запросу. Это должно помочь вам. :-) – pyrocumulus

+0

Используйте ограничение проверки, тогда вам не нужна эта конструкция. –

+0

@frank: я пытался изучить горячие транзакции, это просто пример;) – Strae

ответ

6

Как уже говорит Йоханнес: вы смешиваете обычный SQL с PL/pgSQL, языком хранимой процедуры. Ссылка, которую предлагает Johannes, должна объяснить вам концепцию хранимых процедур.

Полагаю, вы делаете это как скрипт? Выполнение одного заявления за другим? Боюсь, вы можете делать то, что хотите делать внутри хранимой процедуры или функции, как вы могли бы ее назвать. Это происходит потому, что, когда вы выполняете инструкции таким образом, каждый оператор стоит сам по себе без каких-либо отношений или информации относительно других операторов.

Кроме того, вы можете посмотреть следующую ссылку для получения дополнительной информации о том, как использовать IF ... THEN ... ELSE ... END IF; условные обозначения внутри plpgsql: link.


EDIT:

Я не знаю, если ROLLBACK разрешено в этой точке (потому что каждая хранимая процедура уже в своей собственной транзакции), но вы должны быть в состоянии понять, что за самостоятельно используя обширную документацию @http://www.postgresql.org. Вот пример функции с кодом в нем, а также демонстрирует некоторые другие синтаксис:

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; 

Однако, если вы действительно собираетесь этот путь, я рекомендую использовать менеджер GUI DB. Это легче изучить.

+0

Хорошо, я понял и прочитал ссылку johannes (что я не видел в первый раз, когда я читал ответ). Можете ли вы опубликовать пример того, как может выглядеть sql, который я написал в PL/pgSQL? Спасибо .. – Strae

+0

Спасибо, я нашел документацию postgres очень хорошей и хорошо написанной .. просто немного «большой», но это нормально, я купил 3-точную бумажную версию, и я обещаю прочитать их все. Я просто не могу понять, почему оператор if может использоваться в простом sql, когда в mysql он также может использоваться. – Strae

+0

Хо, последнее: я столкнулся с ошибками и даже в разделе оператора руководства, но я не могу найти значение ': =' .. для чего это используется? – Strae

2

Вы, кажется, используют простой SQL но IF заявление является частью процедурного языка PL/pgSQL, который является частью PostgreSQL.

+1

может лучше объяснить это? – Strae

1

Если вы хотите, чтобы избежать, если вы могли бы переписать код, как:

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; 

Да, это глупо :).

+0

lol im new of postgresql .. я думаю, что понял ваш пример;) – Strae

+0

Это ужасный пример, действительно, это был просто мысленный эксперимент :). –

1

Вы могли бы попытаться изменить, если часть из:

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 

Предполагая v_credit переменная вы определили ранее. IMHO, Postgre предполагает, что запрос SELECT возвращает более одного результата, даже если вы уверены, что он уникален. Поэтому я думаю, вы могли бы попытаться заранее присвоить значение переменной.

+0

для тестирования, я даже попробовал IF 2 = 2 THEN [...], но все равно выбросил ошибку. – Strae

0

Как и SQL и T/SQL Microsoft, вы должны иметь возможность смешивать обычный SQL с PL/pgSQL, если они находятся в правильной последовательности. Вот пример, где последовательность имеет значение в смешанном запросе SQL/PL:

Вы не можете обертывать условные выражения внутри курсора - вы должны поместить курсор внутрь условного оператора. Если вы последовательность наоборот, вы получите ту же ошибку, как вы видели, «ОШИБКА: ошибка синтаксиса или вблизи„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$ 

Я новичок в PostgresSQL; эта функция является лишь примером.

Смежные вопросы