Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use variables in a postgresql function for loop query

I have a rather complicated function in postgresql (Version 9.4.4) that I need a bit of help with.

I have a loop (with lots of work below) declared like this inside of my function:

CREATE OR REPLACE function getRSI(
    psymbol varchar,
    pstarttime timestamp with time zone,
    pendtime timestamp with time zone,
    pduration double precision,
    ptable varchar
    )
 RETURNS SETOF rsi AS
 $BODY$
 declare
    row_data record;
    -- some variables
 begin
    FOR row_data IN SELECT datetime, value FROM "4" WHERE symbol = 'AAPL' 
    AND datetime BETWEEN '2015-11-23 09:30:00 -0500' AND 
    '2015-11-23 15:59:59-0500' LOOP
       -- enter code here
    END LOOP;
 end
 $BODY$ LANGUAGE plpgsql

This works perfectly, I can get the result of my function and have it crunch all the numbers for me.

I would like to get the loop to work like this:

FOR row_data in select datetime, value from quote_ident(ptable) 
where symbol = quote_literal(psymbol) and datetime 
between quote_literal(pstarttime) AND quote_literal(pendtime) LOOP

where ptable, psymbol, pstarttime and pendtime are variables passed from the function call.

But I would be happy having to hardcode a table and getting the other three things to be based on a variable:

FOR row_data in select datetime, value from "4" where symbol =
quote_literal(psymbol) and datetime between quote_literal(pstarttime)
AND quote_literal(pendtime) LOOP

Yes, I know that I have a table named after a number, nothing I can do about it in my current setup.

When I try to call the function with either of the above setups, I just get a blank. Any help would be appreciated. I can't find any documentation about using a variable in a for loop so it might not be possible.

like image 349
Ben Hernandez Avatar asked Jan 07 '23 22:01

Ben Hernandez


2 Answers

You need dynamic SQL with EXECUTE - but only to parameterize the table name (or other identifiers) - not necessary to parameterize values.

And do not concatenate parameter values into the query. That's more expensive and error prone than necessary. Use the USING clause of EXECUTE instead.

FOR row_data IN
   EXECUTE '
    SELECT datetime, value FROM ' || quote_ident(ptable) || '
    WHERE  symbol = $1
    AND    datetime between $2 AND $3'
   USING psymbol, pstarttime, pendtime
LOOP
  -- do stuff
END LOOP;

Or use format():

   EXECUTE format('
    SELECT datetime, value FROM %I 
    WHERE  symbol = $1
    AND    datetime between $2 AND $3', ptable)
   USING psymbol, pstarttime, pendtime

Related:

  • The manual on record types
  • Table name as a PostgreSQL function parameter
  • plpgsql - using dynamic table name in declare statement
like image 112
Erwin Brandstetter Avatar answered Jan 16 '23 22:01

Erwin Brandstetter


change your for loop like this

FOR row_data in execute 'select datetime, value from "4" where symbol =' || 
quote_literal(psymbol)  || 'and datetime between' || quote_literal(pstarttime)
|| 'AND ' || quote_literal(pendtime) LOOP
like image 43
Sathish Avatar answered Jan 16 '23 22:01

Sathish