Postgres SELECT其中WHERE是UUID或字符串

Wai*_*age 21 postgresql

我在Postgres中使用了简化表:

  • 用户模型
    • id(UUID)
    • uid(varchar)
    • 名称(varchar)

我想要一个可以在其UUID id或其文本上找到用户的查询uid.

SELECT * FROM user
WHERE id = 'jsdfhiureeirh' or uid = 'jsdfhiureeirh';
Run Code Online (Sandbox Code Playgroud)

我的查询生成一个,invalid input syntax for uuid因为我显然没有在这个实例中使用UUID.

如何优化此查询或检查该值是否为有效的UUID?

Wai*_*age 45

找到了!转换UUID列以::text停止错误.不确定性能是否打击,但在大约5000行上我得到的性能不仅仅是足够的.

SELECT * FROM user
WHERE id::text = 'jsdfhiureeirh' OR uid = 'jsdfhiureeirh';

SELECT * FROM user
WHERE id::text = '33bb9554-c616-42e6-a9c6-88d3bba4221c' 
  OR uid = '33bb9554-c616-42e6-a9c6-88d3bba4221c';
Run Code Online (Sandbox Code Playgroud)


Jos*_*den 7

我最初误解了这个问题。如果您想“安全地”尝试将字符串强制转换为UUID,则可以编写一个函数来捕获invalid_text_representation异常并返回null从对另一个问题的答案进行了修改):

CREATE OR REPLACE FUNCTION uuid_or_null(str text)
RETURNS uuid AS $$
BEGIN
  RETURN str::uuid;
EXCEPTION WHEN invalid_text_representation THEN
  RETURN NULL;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

SELECT uuid_or_null('INVALID') IS NULL然后将导致true

换句话说(鉴于(true or null) = true),

SELECT * FROM user
WHERE id = uuid_or_null('FOOBARBAZ') OR uid = 'FOOBARBAZ';
Run Code Online (Sandbox Code Playgroud)

原始答案:

Postgres会自动为您将字符串转换为UUID,但是您需要使用有效的UUID。例如:

SELECT * FROM user
WHERE id = '5af75c52-cb8e-44fb-93c8-1d46da518ee6' or uid = 'jsdfhiureeirh';
Run Code Online (Sandbox Code Playgroud)

您还可以让Postgres使用DEFAULT带有扩展uuid_generate_v4()功能的子句为您生成UUID uuid-ossp

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

CREATE TABLE user (  
   id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
   uid TEXT,
   name TEXT
);
Run Code Online (Sandbox Code Playgroud)

  • 对于 200 万行,将 ID 转换为字符串进行查询需要 600 毫秒,而执行上述操作则需要 18 秒。 (2认同)

Lau*_*lbe 7

您可以使用正则表达式进行检查:

SELECT *
FROM user
WHERE ('jsdfhiureeirh' ~ E'^[[:xdigit:]]{8}-([[:xdigit:]]{4}-){3}[[:xdigit:]]{12}$'
       AND id = 'jsdfhiureeirh')
      OR uid = 'jsdfhiureeirh';
Run Code Online (Sandbox Code Playgroud)

  • 这个答案绝对应该被更多人考虑。存储过程并不适合每个人使用。在我的情况下,我非常希望能够只修改查询。我的问题是我有一个文本列,有时我会有 UUID,但有时会有其他数据格式。当我有 UUID 时,我知道联接应该起作用。这个答案在我的情况下是完美的,因为它完全避免了铸造错误 (2认同)
  • 就我而言,这个解决方案要快得多,感谢您的帮助! (2认同)
  • Postgres 中不保证执行顺序,因此您不能确定如果正则表达式不匹配,它会短路:https://www.postgresql.org/docs/10/sql-expressions。 html#SYNTAX-EXPRESS-EVAL 您可以使用 CASE 语句来保证它以正确的顺序发生。 (2认同)