2009-04-29 20 views
11

jestem nowy z PostgreSQL, a ja już mam pierwszy problem ..PostgreSQL „IF” błąd składni

pisałem jakiś kod, aby zrozumieć, jak działają transakcji, po ręcznym krok po kroku.

Dla skrótu, utworzyłem 2 tabele, użytkownika i ruchy: w pierwszym są kolumny nazwy, e-mail i kredytu, w drugim kolumny od, do, import.

Więc starałem ten sposób:

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; 

zawsze pojawia się błąd:

ERROR: syntax error at or near "IF"

gdzie jestem w błędzie?

PS: Nie koncentrują się na przykład funkcjonalność, to tylko próba dla mnie do zrozumienia transakcji .. i teraz, klauzula IF ...

+0

Dodałem przykładowy kod na żądanie. To powinno ci pomóc. :-) – pyrocumulus

+0

Użyj ograniczenia sprawdzającego, wtedy nie potrzebujesz tej konstrukcji. –

+0

@frank: Próbowałem nauczyć się gorących transakcji działa, to tylko przykład;) – Strae

Odpowiedz

6

Jak już powiedział Johannes: mieszamy zwykły SQL z PL/pgSQL, językiem procedury składowanej. Łącze, które zapewnia Johannes, powinno wyjaśnić ci pojęcie procedur przechowywanych.

Zakładam, że robisz to jako scenariusz? Wykonywanie jednego zdania po drugim? Obawiam się, że możesz zrobić tylko to, co chcesz zrobić wewnątrz procedury składowanej lub funkcji, jak możesz to nazwać. Dzieje się tak dlatego, że podczas wykonywania instrukcji w ten sposób każde wyrażenie jest niezależne bez relacji lub informacji dotyczących innych instrukcji.

Ponadto można obejrzeć poniższy link, aby uzyskać więcej informacji na temat korzystania z IF ... THEN ... ELSE ... END IF; warunki warunkowe wewnątrz plpgsql: link.


EDIT:

ja nie wiem, czy ROLLBACK jest dozwolone w tym miejscu (bo każda procedura przechowywana jest już we własnym transakcji), ale musi być w stanie zorientować się, że samodzielnie korzystając z obszernej dokumentacji @http://www.postgresql.org. Oto funkcja próbki z kodem w nim także wykazać jakąś inną składnię:

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; 

Jednakże, jeśli naprawdę będzie tą drogą, polecam za pomocą menedżera GUI DB. Łatwiej się tego nauczyć.

+0

Ok, zrozumiałem i przeczytałem link johannesa (którego nie widziałem po raz pierwszy, gdy czytałem odpowiedź). Czy możesz podać przykład, jak może wyglądać sql napisał w PL/pgSQL? Dzięki .. – Strae

+0

Dziękuję kolego, znalazłem dokumentację postgresu bardzo dobrą i dobrze napisaną .. po prostu mało "dużą", ale w porządku, kupiłem 3 tomową wersję papierową i obiecuję przeczytać je wszystkie. Po prostu nie mogę zrozumieć, dlaczego instrukcja if nie może być użyta w zwykłym sql, gdy w mysql może on również zostać użyty. – Strae

+0

Ho, ostatnia rzecz: już googlowałem i nawet w sekcji operatorskiej instrukcji, ale Nie mogę znaleźć znaczenia ": =" ... do czego to służy? – Strae

2

Wydaje się używać zwykłego SQL ale stwierdzenie IF jest częścią języka proceduralnego, który jest częścią PostgreSQL.

+1

może lepiej to wyjaśnić? – Strae

1

Jeśli chcesz uniknąć, jeśli można przepisać kod jako:

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; 

Tak, to jest głupi :).

+0

lol im new z postgresql .. myślę, że zrozumiałem twój przykład;) – Strae

+0

To okropny przykład, naprawdę, to był tylko eksperyment myślowy :). –

1

można spróbować zmodyfikować części, jeżeli od:

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

do

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

Zakładając v_credit jest zmienną zdefiniowano poprzednio. IMHO, Postgre zakłada, że ​​zapytanie SELECT zwraca więcej niż jeden wynik, nawet jeśli jesteś pewien, że jest unikalny. Więc myślę, że mógłbyś wcześniej spróbować przypisać wartość do zmiennej.

+0

za przetestowanie tego, nawet wypróbowałem IF 2 = 2 THEN [...] ale wciąż rzucam błąd .. – Strae

0

Podobnie jak Microsoft SQL i T/SQL, powinieneś być w stanie wymieszać zwykły SQL z PL/pgSQL, jeśli są one we właściwej kolejności. Oto przykład, w którym sekwencja ma znaczenie w mieszanym procencie przechowywanym w języku SQL/PL:

Nie można zawijać instrukcji warunkowych wewnątrz kursora - należy umieścić kursor wewnątrz instrukcji warunkowej. Jeśli nie sekwencję na odwrót, pojawi się ten sam błąd, jak można zauważyć, „BŁĄD: błąd składni na lub w pobliżu«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$ 

Jestem początkujący w PostgresSQL; ta funkcja jest tylko przykładem.

Powiązane problemy