12

私はPostgreSQLを初めて使用し、すでに最初の問題を抱えています..

手動の手順に従って、トランザクションがどのように機能するかを理解するためのコードをいくつか書きました。

簡単に言うと、ユーザーと動きの 2 つのテーブルを作成しました。最初のテーブルには名前、メール、クレジットの列があり、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;

私はいつもエラーが発生します:

エラー: "IF" またはその近くで構文エラーが発生しました

どこが間違っていますか?

PS: 例の機能に焦点を当てないでください。これは、トランザクションを理解するための単なる試行です..そして今、IF 句...

4

5 に答える 5

7

Johannes がすでに言っているように、通常の SQL とストアド プロシージャ言語である PL/pgSQL を混在させています。Johannes が提供するリンクは、ストアド プロシージャの概念を説明するはずです。

これをスクリプトとして実行していると思いますか?次から次へとステートメントを実行しますか? 残念ながら、ストアド プロシージャまたは関数と呼ばれる内部でしか実行できないことがあります。これは、この方法でステートメントを実行している場合、すべてのステートメントが独立しており、他のステートメントに関する関係や情報がないためです。

さらに、IF ... THEN ... ELSE ... END IF の使用方法の詳細については、次のリンクを参照してください。plpgsql 内の条件:リンク.


編集:

その時点で ROLLBACK が許可されているかどうかはわかりません (各ストアド プロシージャは既に独自のトランザクションに含まれているため) . これは、コードを含むサンプル関数であり、他の構文も示しています。

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 マネージャーを使用することをお勧めします。これらすべてを学ぶのは簡単です。

于 2009-04-29T15:16:19.380 に答える
2

プレーンを使用しているようですSQLが、IFステートメントはPL/pgSQLPostgreSQLの一部である手続き型言語の一部です。

于 2009-04-29T15:02:50.223 に答える
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;

はい、これはばかげています:)。

于 2009-04-29T15:17:23.793 に答える
0

Microsoft の SQL や T/SQL と同様に、正しい順序であれば、通常の SQL と PL/pgSQL を混在させることができます。SQL/PL が混在するストアド プロシージャでシーケンスが重要になる例を次に示します。

カーソル内で条件ステートメントをラップすることはできません。カーソルを条件ステートメント内に配置する必要があります。シーケンスを逆にすると、見たのと同じエラーが表示されます。

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 の初心者です。この関数は単なる例です。

于 2012-04-06T16:46:22.377 に答える