【发布时间】:2018-09-25 11:17:09
【问题描述】:
我使用 PostgreSQL 10 并成功运行 CREATE EXTENSION unaccent;。我有一个包含以下内容的 plgsql 函数
whereText := 'lower(unaccent(place.name)) LIKE lower(unaccent($1))';
稍后,根据用户的选择,whereText 可能会添加更多子句。
whereText 最终用在查询中:
placewithkeys := '%'||placename||'%';
RETURN QUERY EXECUTE format('SELECT id, name FROM '||fromText||' WHERE '||whereText)
USING placewithkeys , event, date;
whereText := 'LOWER(unaccent(place.name)) LIKE LOWER(unaccent($1))'; 不起作用,即使我删除了 LOWER 部分。
我做了select __my_function('Τζι');,但我什么也没得到,即使我应该得到结果,因为在数据库中有名字Τζίμα
如果我删除 unaccent 并保留 LOWER 它可以工作,但不适用于重音:τζ 会按原样返回 Τζίμα。 unaccent 似乎引起了问题。
我错过了什么?我怎样才能解决这个问题?
由于有关于语法和可能的 SQLi 的 cmets,我提供了整个函数定义,现在更改为在希腊语中不区分重音和不区分大小写:
CREATE FUNCTION __a_search_place
(placename text, eventtype integer, eventdate integer, eventcentury integer, constructiondate integer, constructioncentury integer, arstyle integer, artype integer)
RETURNS TABLE
(place_id bigint, place_name text, place_geom geometry)
AS $$
DECLARE
selectText text;
fromText text;
whereText text;
usingText text;
placewithkeys text;
BEGIN
fromText := '
place
JOIN cep ON place.id = cep.place_id
JOIN event ON cep.event_id = event.id
';
whereText := 'unaccent(place.name) iLIKE unaccent($1)';
placewithkeys := '%'||placename||'%';
IF constructiondate IS NOT NULL OR constructioncentury IS NOT NULL OR arstyle IS NOT NULL OR artype IS NOT NULL THEN
fromText := fromText || '
JOIN construction ON cep.construction_id = construction.id
JOIN construction_atype ON construction.id = construction_atype.construction_id
JOIN construction_astyle ON construction.id = construction_astyle.construction_id
JOIN atype ON atype.id = construction_atype.atype_id
JOIN astyle ON astyle.id = construction_astyle.astyle_id
';
END IF;
IF eventtype IS NOT NULL THEN
whereText := whereText || 'AND event.type = $2 ';
END IF;
IF eventdate IS NOT NULL THEN
whereText := whereText || 'AND event.date = $3 ';
END IF;
IF eventcentury IS NOT NULL THEN
whereText := whereText || 'AND event.century = $4 ';
END IF;
IF constructiondate IS NOT NULL THEN
whereText := whereText || 'AND construction.date = $5 ';
END IF;
IF constructioncentury IS NOT NULL THEN
whereText := whereText || 'AND construction.century = $6 ';
END IF;
IF arstyle IS NOT NULL THEN
whereText := whereText || 'AND astyle.id = $7 ';
END IF;
IF artype IS NOT NULL THEN
whereText := whereText || 'AND atype.id = $8 ';
END IF;
whereText := whereText || '
GROUP BY place.id, place.geom, place.name
';
RETURN QUERY EXECUTE format('SELECT place.id, place.name, place.geom FROM '||fromText||' WHERE '||whereText)
USING placewithkeys, eventtype, eventdate, eventcentury, constructiondate, constructioncentury, arstyle, artype ;
END;
$$
LANGUAGE plpgsql;
【问题讨论】:
-
嗨 slevin:那是什么语言?希腊语?既然我显然不会说,你能否提供一个带口音的单词列表以及没有口音的单词应该是什么样子?德语看起来效果很好
select lower(unaccent('MÜNSTER')) like lower(unaccent('mÜNsTer')); -
注意:你的代码存在sql注入漏洞
-
@JimJones 是的,这是希腊语。一般来说,所有元音都有一个简单的标记来表示音调/重音。所以 χαρτί, ήλιος, ξύλο, βάση 有口音,而 χαρτι, ηλιος, ξυλο, βαση 他们没有。注意 ι, η, υ, α 中缺少一个简单的标记。这对解决方案有何帮助?
-
@PavelStehule 因为这部分
placewithkeys := '%'||placename||'%';我假设?请详细说明。谢谢。 -
我认为问题在于 unaccent 不支持希腊语。我要求提供示例以便我可以测试,以防万一它是另一种语言。
标签: postgresql plpgsql dynamic-sql accent-insensitive unaccent