Honestly, I have no much experience with postgres and sql at all.
I'm Trying to make function with dynamic table and column names using EXECUTE FORMAT(...) query. But whatever I tried FORMAT doesn't consider values provided for type arguments such as %s and %I. And googling didn't help due to lack of useful information. I saw many examples and my code doesn't differentiate from examples but doesn't work. I made fiddle here -> db-fiddle
Here's my DDL code:
CREATE TABLE IF NOT EXISTS tbl (
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL
);
CREATE FUNCTION occurences_number(varchar, varchar) RETURNS integer AS '
DECLARE
text varchar := LOWER($1);
str varchar := LOWER($2);
BEGIN
RETURN (CHAR_LENGTH(text) - CHAR_LENGTH(REPLACE(text, str, " "))) / CHAR_LENGTH(str);
END; '
LANGUAGE PLPGSQL;
CREATE FUNCTION records_with_string(regclass, varchar, varchar)
RETURNS integer AS '
DECLARE
result integer;
tbl ALIAS FOR $1;
col ALIAS FOR $2;
str ALIAS FOR $3;
BEGIN
EXECUTE format("SELECT COUNT(*) FROM %I WHERE occurences_number(%I, %s) > 0", tbl::varchar, col::varchar, str::varchar)
INTO result;
RETURN result;
END; '
LANGUAGE PLPGSQL;
And here's query:
INSERT INTO tbl VALUES ('a', 'aaa bbb ccc ddd'), ('b', 'aaa bbb'), ('c', 'ccc ddd'), ('d', 'aaa ccc ddd'), ('e', 'aaa bbb ccc ddd eee');
SELECT "records_with_string"('tbl'::regclass, 'last_name', 'eee') FROM tbl;
The result of the query is:
Query Error: error: column "SELECT COUNT(*) FROM %I WHERE occurences_number(%I, %s) > 0" does not exist
What do I do wrong?
UPDATE db-fiddle doesn't accept $$
You should not use double quotes for string literals but only single quotes and you should use %L
for SQL literals when using format
:
select * from tbl;
first_name | last_name
------------+---------------------
a | aaa bbb ccc ddd
b | aaa bbb
c | ccc ddd
d | aaa ccc ddd
e | aaa bbb ccc ddd eee
(5 rows)
CREATE OR REPLACE FUNCTION occurences_number(varchar, varchar) RETURNS integer AS
$$
DECLARE
text varchar := LOWER($1);
str varchar := LOWER($2);
BEGIN
RETURN (CHAR_LENGTH(text) - CHAR_LENGTH(REPLACE(text, str, ' '))) / CHAR_LENGTH(str);
END;
$$
LANGUAGE PLPGSQL;
CREATE FUNCTION
CREATE OR REPLACE FUNCTION records_with_string(tbl varchar, col varchar, str varchar)
RETURNS integer AS
$$
DECLARE
result integer;
BEGIN
EXECUTE format('SELECT COUNT(*) FROM %I WHERE occurences_number(%L, %L) > 0', tbl, col, str)
INTO result;
RETURN result;
END;
$$
LANGUAGE PLPGSQL;
CREATE FUNCTION
SELECT "records_with_string"('tbl', 'last_name', 'eee') FROM tbl;
records_with_string
---------------------
0
0
0
0
0
(5 rows)