如何将触发器函数写在pl/pgsql中的另一个函数内部?

问题描述 投票:0回答:1

我正在尝试在嵌套函数中编写触发器函数:

create or replace function get_book(val1 varchar, val2 varchar default null, val3 varchar default null)
returns table(books varchar, its_category varchar)
language plpgsql

as 
$$
    declare 
    fav_book varchar(255) := val1;
    author_name varchar(255):= val2;
    category_name varchar(255) := val3;
    
begin 
    if fav_book in(select book_name from books) then 
    
          return query 
          select b.book_name, ca.category 
          from books as b inner join categories as ca on b.category_id = ca.category_id
          where ca.category= category_name;
          
          
    else 
        begin 
            create or update function trigger_insertion()
            returns void 
            language plpgsql
            as $$
                begin 
                    insert into books(book_name)
                    values(fav_book);
                    
                    create or update insert_category_author()
                    returns trigger 
                    language plpgsql
                    as $$
                        declare
                            cat_id int;
                            auth_id int;
                        begin 
                                if category_name in (select category from categories) then 
                                    select category_id into cat_id from categories where category_name = category
                                    update books
                                    set new.category_id = cat_id;

                                else 
                                    begin 
                                        insert into categories(category)
                                        values(category_name);
                                        select category_id into cat_id from categories where category_name = category;
                                        update books
                                        set new.category_id = cat_id;
                                    end;

                                end if;

                                if author_name in (select author from authors) then
                                    select author_id into auth_id from authors where author_name = author
                                    update books
                                    set new.author_id = auth_id;

                                else 
                                    begin 
                                        insert into authors(author)
                                        values(author_name);
                                        select author_id into auth_id from authors where author_name = author;
                                        update books
                                        set new.author_id = auth_id;    
                                    end;
                                end if;
                        end;
                        $$;
                        
                    create trigger update_books_table
                    after insert on books
                    for each row execute procedure insert_category_author();
                    
                end;
                return;
                $$;
                
        end;        
    end if;
end;

return;
$$;

我有三张桌子: Books 表的category_id 列引用category 表中的category_id 列, 和author_id引用author表中的author_id列和book_name列。

作者表有作者列,存储书籍的作者。 类别表有类别列,用于存储书籍的类别。

我想要实现的是检查 fav_book (用户给出的一本书)是否已存在于 books 表中的 book_name 列中,然后显示属于给定书籍同一类别的所有书籍。 如果 fav_book 不存在,则插入该书并触发函数 (insert_category_author) 该函数检查插入书籍的类别和作者,如果它们都已存在于表中(类别和作者),只需获取它们的 id 即可到变量中并更新 books 表的两列(category_id、author_id)。如果它们不存在,则插入它们并进行更新。

我只是想将所有函数嵌套在一个函数(get_book)中。 我不断收到错误,我知道代码中有很多问题,但我找不到实现我的想法的方法。

我得到的错误是:

ERROR:  syntax error at or near "insert"
LINE 27:       insert into books (book_name)
postgresql function triggers plpgsql
1个回答
0
投票

您的 PL/pgSQL 代码中似乎存在一些语法错误和问题。为了实现嵌套函数以及在单个函数中处理书籍、类别和作者的插入和更新逻辑的目标,您需要进行一些更正。下面是修改后的代码:

CREATE OR REPLACE FUNCTION get_book(val1 varchar, val2 varchar DEFAULT NULL, val3 varchar DEFAULT NULL)
RETURNS TABLE(books varchar, its_category varchar)
LANGUAGE plpgsql
AS
$$
DECLARE
    fav_book varchar(255) := val1;
    author_name varchar(255) := val2;
    category_name varchar(255) := val3;
BEGIN
    -- Check if the favorite book exists in the books table
    IF EXISTS (SELECT 1 FROM books WHERE book_name = fav_book) THEN
        -- If it exists, return the books in the same category
        RETURN QUERY
        SELECT b.book_name, ca.category
        FROM books AS b
        INNER JOIN categories AS ca ON b.category_id = ca.category_id
        WHERE b.book_name = fav_book;
    ELSE
        -- If it doesn't exist, insert the book and handle categories and authors
        INSERT INTO books (book_name)
        VALUES (fav_book)
        RETURNING book_name, its_category
        INTO books, its_category;

        -- Insert or update the category
        PERFORM insert_category_author(fav_book, category_name, author_name);

        RETURN NEXT;
    END IF;
END;
$$;

-- This function handles category and author insertion/updating
CREATE OR REPLACE FUNCTION insert_category_author(book_name varchar, category_name varchar, author_name varchar)
RETURNS void
LANGUAGE plpgsql
AS
$$
DECLARE
    cat_id INT;
    auth_id INT;
BEGIN
    -- Insert or update category
    IF category_name IN (SELECT category FROM categories) THEN
        SELECT category_id INTO cat_id FROM categories WHERE category = category_name;
    ELSE
        INSERT INTO categories (category)
        VALUES (category_name)
        RETURNING category_id INTO cat_id;
    END IF;

    -- Insert or update author
    IF author_name IN (SELECT author FROM authors) THEN
        SELECT author_id INTO auth_id FROM authors WHERE author = author_name;
    ELSE
        INSERT INTO authors (author)
        VALUES (author_name)
        RETURNING author_id INTO auth_id;
    END IF;

    -- Update the books table with category_id and author_id
    UPDATE books
    SET category_id = cat_id, author_id = auth_id
    WHERE book_name = book_name;
END;
$$;

以下是一些关键更改和说明:

  1. 我在

    get_book
    函数中组合了检查书籍是否存在、插入书籍以及处理类别和作者的逻辑。

  2. 我创建了一个单独的

    insert_category_author
    函数来处理类别和作者的插入或更新。根据需要在
    get_book
    函数中调用此函数。

  3. RETURNING
    子句用于捕获插入或更新的值(例如,book_name、its_category)并将它们返回给
    get_book
    函数中的调用者。

  4. insert_category_author
    函数中,我们首先检查类别和作者是否已经存在于各自的表中。如果他们这样做了,我们会检索他们的 ID;否则,我们插入它们并检索新的 ID。

  5. 最后,我们根据获取或插入的值使用适当的

    books
    category_id
    更新
    author_id
    表。

请在您的 PostgreSQL 环境中测试此代码,并根据需要进一步调整它以满足您的特定表结构和要求。

© www.soinside.com 2019 - 2024. All rights reserved.