0

老实说,我对 postgres 和 sql 一点经验都没有。

我正在尝试使用 EXECUTE FORMAT(...) 查询使用动态表名和列名来创建函数。但是无论我尝试什么 FORMAT 都不会考虑为类型参数提供的值,例如 %s 和 %I。由于缺乏有用的信息,谷歌搜索没有帮助。我看到了很多示例,我的代码与示例没有区别,但不起作用。我在这里做了小提琴-> db-fiddle

这是我的 DDL 代码:

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;

这是查询:

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;

查询的结果是:

查询错误:错误:列“SELECT COUNT(*) FROM %I WHEREoccurrences_number(%I, %s) > 0”不存在

我做错了什么?

UPDATE db-fiddle 不接受 $$

4

2 回答 2

2

您不应将双引号用于字符串文字,而应仅使用单引号,并且在%L使用 时应将其用于 SQL 文字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)
于 2020-06-16T08:30:18.330 回答
0

为避免与普通引号发生冲突,您需要使用dollar quotes(基本上是两个$字符,它们之间有一些东西。有些东西可以是空的,但开始引号和结束引号必须匹配):


CREATE TABLE IF NOT EXISTS ztbl (
    first_name VARCHAR(100) NOT NULL,
    last_name VARCHAR(100) NOT NULL
);

INSERT INTO ztbl(first_name, last_name) VALUES ('Barack' , 'Obama') , ('Donald' , 'Trump') ;

CREATE FUNCTION occurences_number(varchar, varchar) RETURNS integer AS
$zz$ -- <<-- here
DECLARE
  txt varchar := LOWER($1);
  str varchar := LOWER($2);
BEGIN
  RETURN (CHAR_LENGTH(txt) - CHAR_LENGTH(REPLACE(txt, str, '' ))) / CHAR_LENGTH(str);
END;
$zz$ -- <<-- here
LANGUAGE PLPGSQL;


CREATE FUNCTION records_with_string(regclass, varchar, varchar)
RETURNS integer AS
$zzz$ -- <<-- here
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, %L ) > 0 -- <<-- here
        ;', tbl::varchar, col::varchar, str::varchar)
  INTO result;
  RETURN result;
END;
$zzz$ -- <<-- here
LANGUAGE PLPGSQL;

SELECT records_with_string('ztbl', 'first_name', 'a');
于 2020-06-16T08:39:57.643 回答