SELECT 查询 PostgreSQL 中的西里尔符号

Cyrillic symbols in SELECT query PostgreSQL

我有一个电报机器人(Aiogram,Python),它连接到 PostgreSQL 数据库。

如果用户输入某个用户名(西里尔文、俄文或乌克兰文),bot 应该 return 关于此用户的完整信息,存储在数据库中。

问题是:当机器人查询数据库时,使用用户名例如“Сергій”,它return什么都没有,尽管数据库中存在信息。

SELECT * 
FROM users 
WHERE username = 'Сергій';

我发现问题出在像 'c' 或 'i' 这样的符号中,它们看起来很相似,但在 UTF-8 中有不同的十六进制代码。如果我们以这种方式更改查询,一切正常

SELECT * 
FROM users 
WHERE username LIKE '_ерг_й';

我已经将数据库编码更改为UTF-8,但仍然有这个问题。 如果我直接从数据库复制用户名并将其粘贴到 bot 的输入字段中 - 它有效。

这是我的代码的主要片段:

@dp.message_handler()
async def username_input_handler(message: Message):
    username = message.text

    answer_text = await db.search_by_username(username)
    await message.answer(text=answer_text)

# database class
class Database():
    ...
    async def search_by_username(username):
        query = "SELECT * FROM users WHERE username LIKE "
        user = await self.pool.execute(query, username)
        return user
    ...

更新:

只有在查询 'users' table 时才会出现问题。 table 的数据是从 .txt 文件导入的。

运行 对另一个 table 的相同查询工作正常。

如果用户输入的字符与数据库中的字符完全相同,则查询将起作用,但显然它们不是。您可能需要相似性搜索:

CREATE EXTENSION pg_trgm;

CREATE INDEX ON users USING gist (username gist_trgm_ops);

SELECT *
FROM users
ORDER BY username <-> 'Сергій'
LIMIT 1;

对于像 Сергій 这样的短名称,这可能不会令人满意。如果Сі都是错误的字符,则只剩下一个八卦可以匹配:ерг。这可能找不到您要查找的最接近的匹配项。

您可能需要编写一个函数 cyrillic_normalize 将每个非西里尔字母替换为“最接近的”西里尔字母,例如

CREATE FUNCTION cyrillic_normalize(text) RETURNS text
   LANGUAGE sql AS
$$SELECT translate (, 'Ci', 'Сі')$$;

其中第一个字符串包含拉丁字母,第二个字符串包含相应的西里尔字母。

然后将您的查询更改为

WHERE cyrillic_normalize(username) = cyrillic_normalize('Сергій')