我正在尝试提出以下请求
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
错误,我不明白。
答案 0 :(得分:3)
你可以在plpgsql中编写自己的强制转换功能。
CREATE OR REPLACE FUNCTION to_timestamp_ignore_errors(text) RETURNS timestamp AS $$ BEGIN RETURN $1::timestamp; EXCEPTION WHEN OTHERS THEN RETURN NULL; END; $$ LANGUAGE plpgsql IMMUTABLE STRICT; postgres=# select to_timestamp_ignore_errors('bbbb'); to_timestamp_ignore_errors ---------------------------- (1 row) postgres=# select to_timestamp_ignore_errors('2013-08-16'); to_timestamp_ignore_errors ---------------------------- 2013-08-16 00:00:00 (1 row)
其他可能性是在投射前进行格式检查 - 一些初始版本
CREATE OR REPLACE FUNCTION to_timestamp_ignore_errors(text) RETURNS timestamp AS $$ -- regular should be richer SELECT CASE WHEN $1 ~ '^\d{4}-\d{2}-\d{2}$' THEN $1::timestamp ELSE NULL END; $$ LANGUAGE SQL; CREATE FUNCTION postgres=# select to_timestamp_ignore_errors('2013-08-16'); to_timestamp_ignore_errors ---------------------------- 2013-08-16 00:00:00 (1 row) postgres=# select to_timestamp_ignore_errors('bbbb'); to_timestamp_ignore_errors ---------------------------- (1 row)
在9.2上测试
当存在最小错误时,基于正则表达式的版本应该更快一点(30%),并且当存在大量错误时实际上更快,因此这种解决方案更可取。因此,最好的解决方案是清理数据并使用好的类型。
答案 1 :(得分:2)
我认为这里有一个更基本的问题。时间格式不好?我假设,从SQL的上下文中,我们记录了某人登录某个系统的时间。谁产生那个时间(可能是数据库,或者你手动组装时间)需要正确地完成它。获得时间并保存它是我们应该能够可靠地完成的事情。
编写代码来解决垃圾数据是没有意义的。确保数据有效。