仅在存在扩展名时才调用函数

时间:2018-02-23 07:26:25

标签: postgresql

我需要使用函数UNACCENT来删除WHERE CLAUSE中的变音符号,但仅在安装了此扩展名的情况下才使用普通字符串比较。

考虑表A和B,它可以有数十万行(历史)。然后我从A加到B并在B中寻找一个特定的字符串,但是不想要检查变音符号,并且显然必须快速几乎与正常比较相同(在更多字段中搜索的速度必须相同)

CREATE EXTENSION unaccent;
--DROP EXTENSION unaccent;

DROP TABLE IF EXISTS A;
DROP TABLE IF EXISTS B;

CREATE TEMPORARY TABLE A (id serial, cost numeric, b_id int);
CREATE TEMPORARY TABLE B (id serial, name varchar, surname varchar);

INSERT INTO B(id, name, surname) SELECT gen.id AS id, 'Some test name' || gen.id as name, 'Some test surname' || gen.id as surname FROM (SELECT generate_series(1,10000) as id) gen;
INSERT INTO A(id, cost, b_id) SELECT gen.id AS id, random() * 1000 as cost, (gen.id -1 ) / 10 + 1 FROM (SELECT generate_series(1,100000) as id) gen;

-- this cost 115 ms
SELECT * FROM A
LEFT OUTER JOIN B ON B.id = A.b_id
WHERE 
    B.name ILIKE '%e%' AND 
    B.surname ILIKE '%e%'

-- this cost 412 ms OR crash where not instaled extension
SELECT * FROM A
LEFT OUTER JOIN B ON B.id = A.b_id
WHERE 
    CASE WHEN (SELECT EXISTS ( SELECT 1 FROM pg_extension WHERE extname = 'unaccent' AND extversion IS NOT NULL) LIMIT 1) THEN unaccent(B.name) ILIKE '%e%' ELSE B.name ILIKE '%e%' END AND 
    CASE WHEN (SELECT EXISTS ( SELECT 1 FROM pg_extension WHERE extname = 'unaccent' AND extversion IS NOT NULL) LIMIT 1) THEN unaccent(B.surname) ILIKE '%e%' ELSE B.surname ILIKE '%e%' END

我需要第二个选择与第一个选择相同的速度,并且在未扩展时不会崩溃。

感谢您的帮助。帕维尔

1 个答案:

答案 0 :(得分:0)

您不能在单个SQL语句中执行此操作,因为查询在执行之前会被解析,如果unaccent不存在,则会出现解析错误。

有两种可能性:

  1. 运行两个查询:第一个查询是否存在扩展名,并根据第一个查询的结果构建第二个查询。

  2. 您设置了SAVEPOINT,然后尝试unaccent查询,如果失败,则ROLLBACK TO SAVEPOINT并尝试其他查询。

    在PL / pgSQL中,您可以使用BEGIN ... EXCEPTION ... END块对其进行编码。