У меня проблема с этим кодом, когда я пытаюсь ввести значения в таблицу транзакций - PullRequest
0 голосов
/ 12 октября 2019

Итак, я настраиваю схему, в которой я могу вводить транзакции из записи в журнале, независимые друг от друга, но также зависящие друг от друга (в основном, чтобы гарантировать, что дебит = кредит). Я настроил таблицы, функции и триггера. Затем, когда я пытаюсь ввести значения в таблицу транзакций, я получаю сообщение об ошибке ниже. Я делаю все это в pgAdmin4.

CREATE TABLE transactions (
    transactions_id UUID PRIMARY KEY DEFAULT uuid_generate_v1(),
    entry_id INTEGER NOT NULL,
    post_date DATE NOT NULL,
    account_id INTEGER NOT NULL,
    contact_id INTEGER NULL,
    description TEXT NOT NULL,
    reference_id UUID NULL,
    document_id UUID NULL,
    amount NUMERIC(12,2) NOT NULL
);

CREATE TABLE entries (
    id UUID PRIMARY KEY,
    test_date DATE NOT NULL,
    balance NUMERIC(12,2)
    CHECK (balance = 0.00)
);

CREATE OR REPLACE FUNCTION transactions_biut()
    RETURNS TRIGGER
    LANGUAGE plpgsql
    AS $$
    BEGIN
        EXECUTE 'INSERT INTO entries (id,test_date,balance)
        SELECT
            entry_id,
            post_date,
            SUM(amount) AS ''balance''
        FROM
            transactions
        GROUP BY
            entry_id;';
    END;
    $$;

CREATE TRIGGER transactions_biut
    BEFORE INSERT OR UPDATE ON transactions
FOR EACH ROW EXECUTE PROCEDURE transactions_biut();
INSERT INTO transactions (
    entry_id,
    post_date,
    account_id,
    description,
    amount
)
VALUES
    (
        '1',
        '2019-10-01',
        '101',
        'MISC DEBIT: PAID FOR FACEBOOK ADS',
        -200.00
    ),
    (
        '1',
        '2019-10-01',
        '505',
        'MISC DEBIT: PAID FOR FACEBOOK ADS',
        200.00
    );

После выполнения этого ввода я получаю следующую ошибку:

ERROR:  column "id" of relation "entries" does not exist
LINE 1: INSERT INTO entries (id,test_date,balance)
                             ^
QUERY:  INSERT INTO entries (id,test_date,balance)
        SELECT
            entry_id,
            post_date,
            SUM(amount) AS "balance"
        FROM
            transactions
        GROUP BY
            entry_id;
CONTEXT:  PL/pgSQL function transactions_biut() line 2 at EXECUTE
SQL state: 42703

Ответы [ 2 ]

1 голос
/ 12 октября 2019

Здесь есть несколько проблем:

  • Вы ничего не возвращаете из функции триггера => должно быть return NEW или return OLD, поскольку вы ничего не модифицируете
  • Поскольку вы запускаете триггер перед каждой строкой, он обязательно завершится неудачей для любой транзакции, которая не равна 0 => может быть, вы хотите отложить constraint trigger?
  • Вы не группируете поpost_date, поэтому ваш выбор должен потерпеть неудачу
  • Вы определили entry_id как INTEGER, но entries.id имеет тип UUID

Также обратите внимание, что этона самом деле не будет масштабироваться (вы суммируете все транзакции за все дни, так что это будет становиться все медленнее и медленнее ...)

0 голосов
/ 14 октября 2019

@ chirs Мне удалось выяснить, как создать функционирующее решение, используя триггеры на уровне операторов:

CREATE TABLE transactions (
    transactions_id UUID PRIMARY KEY DEFAULT uuid_generate_v1(),
    entry_id INTEGER NOT NULL,
    post_date DATE NOT NULL,
    account_id INTEGER NOT NULL,
    contact_id INTEGER NULL,
    description TEXT NOT NULL,
    reference_id UUID NULL,
    document_id UUID NULL,
    amount NUMERIC(12,2) NOT NULL
);

CREATE TABLE entries (
    entry_id INTEGER PRIMARY KEY,
    post_date DATE NOT NULL,
    balance NUMERIC(12,2),
    CHECK (balance = 0.00)
);

CREATE OR REPLACE FUNCTION transactions_entries() RETURNS TRIGGER AS $$
    BEGIN
        IF (TG_OP = 'DELETE') THEN
            INSERT INTO entries
                SELECT o.entry_id, o.post_date, SUM(o.amount) FROM old_table o GROUP BY o.entry_id, o.post_date;
        ELSIF (TG_OP = 'UPDATE') THEN
            INSERT INTO entries
                SELECT o.entry_id, n.post_date, SUM(n.amount) FROM new_table n, old_table o GROUP BY o.entry_id, n.post_date;
        ELSIF (TG_OP = 'INSERT') THEN
            INSERT INTO entries
                SELECT n.entry_id,n.post_date, SUM(n.amount) FROM new_table n GROUP BY n.entry_id, n.post_date;
        END IF;

        RETURN NULL; -- result is ignored since this is an AFTER trigger
    END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER transactions_ins
    AFTER INSERT ON transactions
    REFERENCING NEW TABLE AS new_table
    FOR EACH STATEMENT EXECUTE PROCEDURE transactions_entries();
CREATE TRIGGER transactions_upd
    AFTER UPDATE ON transactions
    REFERENCING OLD TABLE AS old_table NEW TABLE AS new_table
    FOR EACH STATEMENT EXECUTE PROCEDURE transactions_entries();
CREATE TRIGGER transactions_del
    AFTER DELETE ON transactions
    REFERENCING OLD TABLE AS old_table
    FOR EACH STATEMENT EXECUTE PROCEDURE transactions_entries();

Есть мысли по оптимизации?

...