- How do I reuse the value returned by - paircalled in the function below?- 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;- I know that the SQL query language doesn't support storing simple values in variables as does a typical programming language. So, I looked at - WITHQueries (Common Table Expressions), but I'm not sure if I should use- WITH, and anyway, I couldn't figure out the correct syntax for what I'm doing.
- Here's my SQLFiddle and my original question about storing chats & messages in PostgreSQL. This function inserts-if-not-exists then inserts. I'm not using a transaction because I want to keep things fast, and storing a chat without messages is not so bad but worse the other way around. So, query order matters. If there's a better way to do things, please advise. 
- I want to reuse the value mainly to speed up the code. But, does the SQL interpreter automatically optimize the function above anyway? Still, I want to write good, DRY code. 
            Asked
            
        
        
            Active
            
        
            Viewed 790 times
        
    0
            
            
        3 Answers
2
            Since the function body is procedural, use the plpgsql language as opposed to 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;
Also, if the result to reuse is pair($1,$2) you may store it into a variable:
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;
 
    
    
        ma11hew28
        
- 121,420
- 116
- 450
- 651
 
    
    
        Daniel Vérité
        
- 58,074
- 15
- 129
- 156
- 
                    Why does the function body being procedural merit using PL/pgSQL? – ma11hew28 Mar 15 '14 at 19:04
- 
                    @MattDiPasquale: PL stands for procedural language, it provides what SQL lacks in terms of variables and execution control. The advantage of SQL as a func language is the potential inlining of single SELECTs, but it doesn't apply in this case of two INSERTs. – Daniel Vérité Mar 17 '14 at 12:43
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;
It will only insert into messages if it exists in chats.
 
    
    
        Clodoaldo Neto
        
- 118,695
- 26
- 233
- 260
- 
                    Thanks, Clodoaldo! But, I want it to insert into `messages` even if the row already exists in `chats` so that you can add multiple messages to one chat. By chat, I mean conversation, or thread. – ma11hew28 Mar 14 '14 at 20:24
0
            
            
        - I actually don't have an answer for this part of your question, but I'll address it anyway because Markdown SUCKS and Stack Overflow doesn't support the - startattribute on the- olelement.
- OK. Now, that we're at 2, :-) PostgreSQL functions are transactional. So, order actually doesn't matter since both inserts will be committed together in one transaction. 
- No, the optimizer only pre-evaluates immutable functions when they're called with constant (not variable) arguments, e.g., - pair(4, 5). See Function Volatility Categories.
