3

我正在尝试提出以下请求

SELECT login, time FROM table 
  WHERE time::timestamp <= (CURRENT_TIMESTAMP - interval '5' month);

其中 time 是一个包含时间戳的文本字段。

当时间格式不正确时,有没有一种方法可以忽略产生强制转换错误的行?

我试过以下

SELECT login, time FROM table 
  WHERE (((CURRENT_TIMESTAMP - interval '6' month)::text || time)::timestamp
    <= (CURRENT_TIMESTAMP - interval '5' month);

但首先,这并不漂亮,其次,它会导致ERROR: time zone displacement out of range错误,我不明白。

4

2 回答 2

5

您可以在 plpgsql 中编写自己的转换函数并进行错误处理。

创建或替换函数 to_timestamp_ignore_errors(text)
返回时间戳为 $$
开始
  返回 $1::timestamp;
其他情况除外
  返回空值;
结尾;
$$ 语言 plpgsql 不可变严格;

postgres=# 选择 to_timestamp_ignore_errors('bbbb');
 to_timestamp_ignore_errors
----------------------------

(1 行)

postgres=# 选择 to_timestamp_ignore_errors('2013-08-16');
 to_timestamp_ignore_errors
----------------------------
 2013-08-16 00:00:00
(1 行)

其他可能性是在投射前进行格式检查 - 一些初始版本

创建或替换函数 to_timestamp_ignore_errors(text)
返回时间戳为 $$
-- 正规的应该更丰富
SELECT CASE WHEN $1 ~ '^\d{4}-\d{2}-\d{2}$' THEN $1::timestamp ELSE NULL END;
$$ 语言 SQL;       
创建函数
postgres=# 选择 to_timestamp_ignore_errors('2013-08-16');
 to_timestamp_ignore_errors
----------------------------
 2013-08-16 00:00:00
(1 行)

postgres=# 选择 to_timestamp_ignore_errors('bbbb');
 to_timestamp_ignore_errors
----------------------------

(1 行)

在 9.2 上测试

当错误最少时,基于正则表达式的版本应该会快一点(30%),而当错误很多时,速度会更快,所以这个解决方案更可取。因此,最好的解决方案是清理数据并使用好的类型。

于 2013-08-08T04:06:20.080 回答
2

我认为这里有一个更根本的问题。时间格式不正确?我假设,从 SQL 的上下文来看,我们正在记录某人登录到某个系统的时间。生成该时间的人(可能是数据库,或者您可能正在手动组装时间)需要正确执行此操作。获得时间并节省时间是我们应该能够可靠地完成的事情。

编写代码来处理垃圾数据是没有意义的。确保数据有效。

于 2013-08-08T03:48:28.793 回答