【问题标题】:SQL: Reuse value returned by function?SQL:重用函数返回的值?
【发布时间】:2014-04-20 04:08:18
【问题描述】:
  1. 如何复用下面函数中调用pair返回的值?

    CREATE FUNCTION messages_add(bigint, bigint, text) RETURNS void AS $$
        INSERT INTO chats SELECT pair($1, $2), $1, $2
            WHERE NOT EXISTS (SELECT 1 FROM chats WHERE id = pair($1, $2));
        INSERT INTO messages VALUES (pair($1, $2), $1, $3);
    $$ LANGUAGE SQL;
    

    我知道SQL query language doesn't support storing simple values in variables 是一种典型的编程语言。所以,我查看了WITH Queries (Common Table Expressions),但我不确定是否应该使用WITH,无论如何,我无法弄清楚我正在做的事情的正确语法。

  2. 这是我的SQLFiddle 和我关于storing chats & messages in PostgreSQL 的原始问题。这个函数inserts-if-not-exists 然后插入。我没有使用事务,因为我想保持快速,并且在没有消息的情况下存储聊天并不是那么糟糕,但反过来更糟。所以,查询顺序很重要。如果有更好的处理方式,请指教。

  3. 我想重用该值主要是为了加快代码速度。但是,SQL 解释器会自动优化上面的功能吗?不过,我还是想写好,DRY 代码。

【问题讨论】:

    标签: sql postgresql variables sql-insert sql-function


    【解决方案1】:
    create function messages_add(bigint, bigint, text) returns void as $$
        with p as (
            select pair($1, $2) as p
        ), i as (
            insert into chats
            select (select p from p), $1, $2
            where not exists (
                select 1
                from chats
                where id = (select p from p)
            )
        )
        insert into messages
        select (select p from p), $1, $3
        where exists (
            select 1
            from chats
            where id = (select p from p)
        )
        ;
    $$ language sql;
    

    如果它存在于聊天中,它只会插入到消息中。

    【讨论】:

    • 谢谢,Clodoaldo!但是,我希望它插入到 messages 中,即使 chats 中已经存在该行,这样您就可以在一个聊天中添加多条消息。聊天是指对话或话题。
    【解决方案2】:

    由于函数体是程序性的,因此请使用plpgsql 语言而不是 SQL:

    CREATE FUNCTION messages_add(bigint, bigint, text) RETURNS void AS $$
    BEGIN
        INSERT INTO chats
            SELECT pair($1, $2), $1, $2
            WHERE NOT EXISTS (SELECT 1 FROM chats WHERE id = pair($1, $2));
        INSERT INTO messages VALUES (pair($1, $2), $1, $3);
    END
    $$ LANGUAGE plpgsql;
    

    另外,如果要重用的结果是pair($1,$2),您可以将其存储到变量中:

    CREATE FUNCTION messages_add(bigint, bigint, text) RETURNS void AS $$
    DECLARE
        pair bigint := pair($1, $2);
    BEGIN
        INSERT INTO chats
            SELECT pair, $1, $2
            WHERE NOT EXISTS (SELECT 1 FROM chats WHERE id = pair);
        INSERT INTO messages VALUES (pair, $1, $3);
    END
    $$ LANGUAGE plpgsql;
    

    【讨论】:

    • 为什么函数体是使用 PL/pgSQL 的程序优点?
    • @MattDiPasquale:PL 代表过程语言,它提供了 SQL 在变量和执行控制方面缺乏的东西。 SQL 作为 func 语言的优势在于可以内联单个 SELECT,但它不适用于两个 INSERT 的情况。
    【解决方案3】:
    1. 我实际上没有答案,因为Markdown SUCKS and Stack Overflow doesn't support the start attribute on the ol element

    2. 好的。现在,我们在 2,:-) PostgreSQL functions are transactional。因此,顺序实际上并不重要,因为两个插入将在一个事务中一起提交。

    3. 不,优化器仅在使用常量(非变量)参数(例如 pair(4, 5))调用不可变函数时对其进行预评估。见Function Volatility Categories

    【讨论】:

      猜你喜欢
      • 2013-05-06
      • 2015-07-07
      • 1970-01-01
      • 2011-03-15
      • 2013-02-26
      • 2016-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多