@IMSoP already shed light upon your syntax error. However, this can be simpler, faster and cleaner in multiple ways.
CREATE OR REPLACE FUNCTION test(_source int, _days int)
RETURNS integer AS
$func$
SELECT count(*)::int
FROM ad a
WHERE a.source = $1
AND a.createdate::date = current_date - $2
$func$ LANGUAGE sql STABLE;
First of all, to subtract days from a date
, you can can just subtract an integer
number. Accordingly I use an integer
parameter here.
You don't need plpgsql for a simple function like this. Use an SQL function instead - which can be "inlined" in the context of a bigger query, and thus optimized better in certain cases.
The function can be STABLE
:
You had a naming conflict built into your function. source
is obviously also a column name. Try to avoid that. A common practice is to prepend variables and parameters with an underscore (which has no special meaning otherwise). You can also table-qualify column names and/or prepend parameter names with the function name (or use positional parameters) to be unambiguous. I did both here.
Assuming id
is your PK column and thus defined NOT NULL
, count(*)
does the same as count(id)
, a bit shorter and cheaper. I cast to integer
, because count() will return a bigint
.
However, going out on a limb here, I suspect your inaccurately named column createdate
is not actually a date
but a timestamp
(essential table definition is missing in the question). In that case it's much more efficient to phrase the query differently:
CREATE OR REPLACE FUNCTION test(_source int, _days int)
RETURNS integer AS
$func$
SELECT count(*)::int
FROM ad a
WHERE a.source = $1
AND a.createdate >= now() - interval '1 day' * $2
AND a.createdate < now() - interval '1 day' * ($2 - 1)
$func$ LANGUAGE sql STABLE;
This expression is sargable and thus more efficient. It can also use a plain index on (createdate)
, or better on (source, createdate)
- important for big tables.
Also demonstrating an alternative way to subtract days. You can multiply the interval '1 day'
. Related: