1

今天早些时候我在摆弄我们的一个数据库,我很好奇如何在 psql 中做一些事情。假设我有如下查询(其中value1mytable中的文本类型):

SELECT * FROM mytable WHERE value1::date < '2013-10-24'::date;

如果所有行都包含可转换的日期字符串,则此方法可以正常工作。第二个它找到一个不能转换为日期的字符串,就会抛出一个错误,如下所示:

ERROR:  invalid input syntax for type date: "C"

这是有道理的,应该发生。但是有没有办法修改上面的查询,这样如果我们遇到 value1 会触发这个错误的行,它就会继续前进,然后跳过那一行?我问的更多是出于好奇而不是实际需要答案,并且在网络上四处挖掘并没有产生太多结果(当然,这可能与我正在使用的关键字有关。)

4

3 回答 3

2

您可以使用 like-pattern 或 regex 仅预过滤value1看起来像日期的 s:

SELECT * FROM mytable WHERE 
 value1 like '____-__-__'
 and value1::date < '2013-10-24'::date;

SELECT * FROM mytable WHERE 
 value1 similar to '[1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]'
 and value1::date < '2013-10-24'::date;

这是在 SQLfiddle - http://sqlfiddle.com/#!1/06916/6

于 2013-10-24T16:24:56.470 回答
1

从技术上讲,我们不能假设 WHERE 子句的评估顺序是从左到右的,这意味着在这样的子句中:

WHERE value1 ~ '^\d{4}-\d{2}-\d{2}$' AND value1::date < '2013-10-24'::date

计划者可能决定先评估value1::date,并且在测试正则表达式之前执行将出错。如果它估计强制转换加比较比正则表达式测试更快,这是一个完全合理的选择。

我认为当前的 PostgreSQL 代码还不够复杂,无法进行特定的重新排列,但是Expression Evaluation Rules中的文档涵盖了这个问题,并且建议使用它CASE来有条件地避免对有问题的表达式进行求值。

遵循此建议,查询将类似于:

SELECT * FROM mytable WHERE 
 CASE WHEN value1 ~ '^\d{4}-\d{2}-\d{2}$'
       THEN value1::date < '2013-10-24'::date
      ELSE false
 END;

此外,如果内容格式似乎与日期匹配,但碰巧是无效的(例如2013-01-32),查询仍然会失败。如果这是一个问题,您应该将强制转换封装在一个捕获错误的函数中:

create function cast_date(text) returns date as $$
begin
  return $1::date;
  exception when others then return null;
end; $$ language plpgsql;

并将测试替换为cast_date(value1) < '2013-10-24'::date

于 2013-10-24T23:39:31.077 回答
0

可能这会起作用:

SELECT * FROM mytable WHERE value1 ~ '^\d{4}-\d{2}-\d{2}$' AND
value1::date < '2013-10-24'::date

正则表达式将检查 value1 是否为所需格式。如果不是,那么就不会发生迄今为止的演员阵容。

于 2013-10-24T16:25:19.043 回答