I'm building this function:
CREATE OR REPLACE FUNCTION qradar21(cliente_in VARCHAR(50), fecha_inicio timestamp, fecha_fin timestamp) RETURNS TABLE(empresa varchar, fecha timestamp, fuente text, total float) AS $$
BEGIN
RETURN QUERY
SELECT qradar_eventos_detalle.empresa, qradar_eventos_detalle.fecha, eventos->>'fuente' AS fuente, sum((eventos->>'total')::float) AS total FROM public.qradar_eventos_detalle
WHERE qradar_eventos_detalle.empresa = 'cliente_in'
AND qradar_eventos_detalle.fecha BETWEEN 'fecha_inicio' AND 'fecha_fin'
GROUP BY qradar_eventos_detalle.empresa, qradar_eventos_detalle.fecha, qradar_eventos_detalle.eventos
ORDER BY total DESC;
END;
$$ LANGUAGE plpgsql
And calling it with:
SELECT * FROM qradar21('BancoXXX', '2018-12-29 12:00:00', '2019-03-03 07:00:00');
Getting this message:
ERROR: invalid input syntax for type timestamp: «fecha_inicio»
LINE 3: AND qradar_eventos_detalle.fecha BETWEEN 'fecha_inicio' A...
If I change the function to use directly the date (AND qradar_eventos_detalle.fecha BETWEEN '2018-12-29 12:00:00' AND '2018-12-30 07:00:00'), it works great.
I don't know what I'm doing wrong... Does anyone know how to pass this "timestamp without time zone" format to the function?
Thank you in advance
Your function uses string literals, rather then referencing the parameters.
You need to remove the single quotes around your parameter names:
WHERE qradar_eventos_detalle.empresa = cliente_in --<< no quotes here!
AND qradar_eventos_detalle.fecha BETWEEN fecha_inicio AND fecha_fin
^
or here
When you call it, it's also better to use proper timestamp literal:
SELECT *
FROM qradar21('BancoXXX', timestamp '2018-12-29 12:00:00', timestamp '2019-03-03 07:00:00');
Related
I am trying to create a function which accepts two arrays, and a date. The function uses the date
in a way where I want hardcoded values of time (with timezone) which are already stated in the function body (in the orig_dataset CTE). Here is my function so far:
CREATE or replace FUNCTION f_loop_in_lockstep_final(_id_arr int[], _counter_arr int[], d_date date)
RETURNS TABLE (uc_name_ varchar)
LANGUAGE plpgsql AS
$func$
DECLARE
_id int;
_counter int;
d_date date;
BEGIN
FOR _id, _counter IN
SELECT *
FROM unnest (_id_arr, _counter_arr) t
LOOP
RETURN QUERY
with orig_dataset as (
select routes
from campaign_routes cr
where cr.created_at between 'd_date 06:00:00 +05:00' and 'd_date 18:00:00 +05:00'
)
-- a couple of further CTE's result in a final CTE called final_cte
select * from final_cte;
END LOOP;
END
$func$;
When I use the following function call:
SELECT * FROM f_loop_in_lockstep_final('{454,454}'::int[]
, '{2,3}'::int[], to_date('2023-01-17','YYYY-MM-DD'));
I receive the following error:
SQL Error [22007]: ERROR: invalid input syntax for type timestamp with time zone: "d_date 06:00:00 +05:00"
Where: PL/pgSQL function f_loop_in_lockstep_final(integer[],integer[],date) line 14 at RETURN QUERY
Well, obviously 'd_date 06:00:00 +05:00' is not a valid date literal.
You need to add a time value to the variable to create a timestamp value based on that:
where cr.created_at between d_date + '06:00:00 +05:00'::time
and d_date + '18:00:00 +05:00'::time
I am not entirely sure that using a time zone offset in a time constant works correctly, so maybe you need:
where cr.created_at between ((d_date + '06:00:00'::time) at time zone '+05:00')
and ((d_date + '18:00:00'::time) at time zone '+05:00')
I am trying to create a function in PostgreSQL that contains a dblink query. The definition of the field that it returns could vary, so I would like to set the field name and data types as input parameters. The error being returned suggests that it isn't referencing the input variables when I name them,
CREATE OR REPLACE FUNCTION validation.dblink_date_check(
username text,
pass text,
srcschemaname text,
srctablename text,
srcdbname text,
datefield text,
datetype text DEFAULT 'date'::text,
srchostname text DEFAULT 'xxx' text,
srcport integer DEFAULT 1234,
OUT max_date timestamp)
RETURNS timestamp
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
AS $BODY$
BEGIN
max_date := (
select c.*
from dblink('dbname='||srcdbname||' host='||srchostname||' port='||srcport||' user='||username||' password='||pass||'',
'select
max('||datefield||') from '||srcschemaname||'.'||srctablename||' a')
--this doesn't work
as c(datefield datetype
));
/*--this works
as c(datefield date
));;*/
raise notice '% - (source): %', date_trunc('second', clock_timestamp()::timestamp),max_date;
return;
End;
$BODY$;
When it doesn't work the error I get is,
ERROR: type "datetype" does not exist
LINE 6: as c(datefield datetype
^
Is there a way to structure the syntax to work (as sometimes it might not be a date, it might be a timestamp, or an integer etc)? I have used 'execute' in other functions (to insert), but using it to select the variable 'max_date' doesn't work.
In POSTGRESQL how to get some value from a table into variable of integer type first and then use it latter.?
Actually I first want to get value in a variable of type integer and then use it in latter select query.
I know all other solution i.e. using join , using ;with clause but I not want all that. I only want what exactly I said.
Any working example will be good. I want all that working in a pgsql
CREATE OR REPLACE FUNCTION public."GetMedLastAdmnstrationDateTime"(_medicationid integer, _alfid integer)
RETURNS TABLE("MedLastAdminDateTime" timestamp without time zone)
LANGUAGE plpgsql
AS $function$
begin
declare _partitiondate timestamp = (select date from table_abc limit 1)
Return Query
select
e."MedDateTime" as "MedLastAdminDateTime"
from public."eMAR" e
where
e."AlfId" = _alfid
and e."MedicationId" = _medicationid
and e."MedDateTime" > _partitiondate::date
order by e."MedDateTime" desc
limit 1
;
END
$function$
;
I have created custom data type. In that I have given alias name of the one field. you will get that in body of the function below.
create type voucher as (
ori numeric, RECEIPT_NO numeric
, receipt_date timestamp with time zone, reg_no character varying
, patient_name character varying, tot_refund_bill_amount double precision
, username character varying );
Thea above statement completes successfully.
Then I want to create a function:
create or replace function billing.voucher_receipt (in_from_date timestamp with time zone, in_to_date timestamp with time zone)
returns setof voucher as $$
declare
out_put voucher%rowtype;
begin
return query(select C.receipt_no as ori ,A.RECEIPT_NO, receipt_date , A.reg_no, patient_name, tot_refund_bill_amount, username
from billing.tran_counter_receipt as a inner join mas_user as b on a.ent_by=b.uid AND cash_book='REFUND'
INNER JOIN billing.tran_BILL AS C ON C.REG_NO=A.REG_NO AND C.CASH_BOOK='GCASH' where receipt_date>=in_from_date and receipt_date<=in_to_date);
end;$$
LANGUAGE plpgsql
Executes without problem.
But when I call it with input like this:
select * from voucher_receipt ('2014-09-25 11:42:44.298346+05:30'
, '2014-09-29 11:03:47.573049+05:30')
it shows an error:
ERROR: function voucher_receipt(unknown, unknown) does not exist
LINE 1: select * from voucher_receipt ('2014-09-25 11:42:44.298346+0...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Can any one help me out from this?
Explain error
You created your function in the schema billing with:
create or replace function billing.voucher_receipt( ...
Then you call without schema-qualification:
select * from voucher_receipt ( ...
This only works while your current setting for search_path includes the schema billing.
Better function
You don't need to create a composite type. Unless you need the same type in multiple places just use RETURNS TABLE to define the return type in the function:
CREATE OR REPLACE FUNCTION billing.voucher_receipt (_from timestamptz
, _to timestamptz)
RETURNS TABLE (
ori numeric
, receipt_no numeric
, receipt_date timestamptz
, reg_no varchar
, patient_name varchar
, tot_refund_bill_amount float8
, username varchar) AS
$func$
BEGIN
RETURN QUERY
SELECT b.receipt_no -- AS ori
, cr.RECEIPT_NO
, ??.receipt_date
, cr.reg_no
, ??.patient_name
, ??.tot_refund_bill_amount
, ??.username
FROM billing.tran_counter_receipt cr
JOIN billing.tran_bill b USING (reg_no)
JOIN mas_user u ON u.uid = cr.ent_by
WHERE ??.receipt_date >= _from
AND ??.receipt_date <= _to
AND b.CASH_BOOK = 'GCASH'
AND ??.cash_book = 'REFUND'
END
$func$ LANGUAGE plpgsql;
Notes
Don't call your parameters "date" while they are actually timestamptz.
RETURN QUERY does not require parentheses.
No need for DECLARE out_put voucher%rowtype; at all.
Your format was inconsistent and messy. That ruins readability and that's also where bugs can hide.
This could just as well be a simple SQL function.
Column names in RETURNS TABLE are visible in the function body almost everywhere. table-qualify columns in your query to avoid ambiguities (and errors). Replace all ??. I left in the code, where information was missing.
Output column names are superseded by names in the RETURNS declaration. So AS ori in the SELECT list is just documentation in this case.
Why schema-qualify billing.tran_bill but not mas_user?
I have this function:
CREATE OR REPLACE FUNCTION check_presence_row(
_id_att_files integer[],
_people_name character varying,
_people_id character varying,
_time_start timestamp without time zone,
_time_end timestamp without time zone
)
RETURNS integer[] AS $BODY$
DECLARE
ids integer array;
BEGIN
ids := (SELECT "id_att_file"FROM att_presence WHERE
"id_att_file" = ANY ("_id_att_files") AND
"id_people" = get_people(
"_people_id",
"_people_name") AND
"time_start" = "_time_start" AND
"time_end" = "_time_end");
RETURN ids;
END;$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
When i call it in PostgreSQL version 9.3 this way:
SELECT check_presence_row(
CAST ('{1,4}' AS int[]),
CAST ('Random Guy' AS varchar),
CAST ('D0388A' AS varchar),
CAST ('2014/08/23 8:04:00' AS timestamp without time zone),
CAST ('2014/08/23 8:34:00' AS timestamp without time zone)
);
it runs OK and return result as desired, but on 9.1 when i send the same query it throws an error:
ERROR: array value must start with "{" or dimension information
CONTEXT: PL/pgSQL function "check_presence_row" line 5 at assignment
********** Error **********
ERROR: array value must start with "{" or dimension information
SQL state: 22P02
Context: PL/pgSQL function "check_presence_row" line 5 at assignment
I found out that when any of the input values of that array is exactly 1 it fails this way but if I change them to some different integer value the pass.... but only on my localhost. Our production server still fails to pass with any value. We tried another computer and that one pass even if the values are 1. Any ideas?
False alert, I just found out that it was caused by that ids := assignment. Because I had one row with id = 1 in att_file table it went wrong on my localhost, while on another computer with empty DB does not. I changed the return to not pass that variabile but only query instead:
CREATE OR REPLACE FUNCTION check_presence_row(
_id_att_files integer[],
_people_name character varying,
_people_id character varying,
_time_start timestamp without time zone,
_time_end timestamp without time zone
)
RETURNS SETOF integer AS
$BODY$
BEGIN
RETURN QUERY SELECT "id_att_file"FROM att_presence WHERE
"id_att_file" = ANY ("_id_att_files") AND
"id_people" = get_people(
"_people_id",
"_people_name") AND
"time_start" = "_time_start" AND
"time_end" = "_time_end";
END;$BODY$
LANGUAGE plpgsql