I have a function with a SELECT
using a SIMILAR TO
expression with a variable and I don't know how to do it:
DECLARE pckg_data cl_data;
DECLARE contacts contacts_reg%ROWTYPE;
DECLARE sim_name varchar;
BEGIN
SELECT client_reg._name,
client_reg.last_name,
client_reg.id_card,
client_reg.address
INTO pckg_data
FROM client_reg WHERE(client_reg._name = (cl_name ||' '|| cl_lastname));
RETURN NEXT pckg_data;
SELECT ('%'||cl_name || ' ' || cl_lastname ||'%') INTO sim_name;
FOR contacts IN SELECT contacts_reg.id
FROM contacts_reg, contactscli_asc, client_reg
WHERE(contacts_reg._name SIMILAR TO sim_name) LOOP
SELECT client_reg._name, client_reg.last_name, client_reg.id_card,
client_reg.address, client_reg.id
INTO pckg_data
FROM client_reg, contactscli_asc WHERE(contactscli_asc.contact = contacts.id
AND client_reg.id = contactscli_asc.client);
END LOOP;
END;
Your query that feeds the loop has CROSS JOIN
over three (!) tables. I removed the last two on the notion that they are not needed. One of them is repeated in the body of the loop. Also consider @kgrittn's note on CROSS JOIN
.
In the body of the loop you select data into a variable repeatedly, which does nothing. I assume you want to return those rows - that's what my edited version does, anyway.
I rewrote the LOOP
construct with a simple SELECT
with RETURN QUERY
, because that's much faster and simpler.
Actually, I rewrote everything in a way that would make sense. What you presented is still incomplete (missing function header) and syntactically and logically a mess.
This is an educated guess, no more:
CREATE FUNCTION very_secret_function_name(cl_name varchar, cl_lastname varchar)
RETURNS TABLE (name varchar, last_name varchar,
id_card int, address varchar, id int)
LANGUAGE plpgsql AS
$func$
DECLARE
_sim_name varchar := (cl_name ||' '|| cl_lastname);
BEGIN
RETURN QUERY
SELECT c._name, c.last_name, c.id_card, c.address, NULL::int
-- added NULL for an id to match the second call
FROM client_reg c
WHERE c._name = _sim_name;
RETURN QUERY
SELECT c._name, c.last_name, c.id_card, c.address, r.id
FROM client_reg c
JOIN contactscli_asc a ON a.client = c.id
JOIN contacts_reg r ON r.id = a.contact
WHERE r._name LIKE ('%' || _sim_name || '%');
END
$func$;
Else, consider the features used.
Some advise:
You can assign a variable at declaration time.
The keyword DECLARE
is only needed once.
Use table aliases to make your code easier to read.
You don't have to enclose the WHERE
clause in parenthesis.
Most likely you don't need SIMILAR TO
and LIKE
does the job faster. I never use SIMILAR TO
. LIKE
or regular expressions (~
) do a better job: