我在postgres中创建了一个复合类型:
CREATE TYPE mytimestamp AS (t timestamp with time zone, o int);
并将其添加到表格
CREATE TABLE t (t0 mytimestamp)
使用自定义转换功能和以下CAST,我能够将带有时区的简单时间戳转换为' mytimestamp'在INSERT语句中:
CREATE CAST (timestamp with time zone AS mytimestamp)
WITH FUNCTION to_mytimestamp(timestamp with time zone) AS ASSIGNMENT;
INSERT INTO t (t0) VALUES(now()); -- works as intended
但是,我似乎无法创建一个使用以下语句的CAST:
CREATE CAST (varchar AS mytimestamp)
WITH FUNCTION to_mytimestamp(varchar) AS ASSIGNMENT;
INSERT INTO t (t0)
VALUES('2014-09-11 13:30:12.564+02'); -- returns 'malformed record literal'
(我需要从varchar,char或text转换 - 但只是实现转换功能并添加相应的CAST似乎不起作用)
我知道我可以通过将查询改为
来实现这一目标INSERT INTO t (t0)
VALUES('2014-09-11 13:30:12.564+02'::varchar); -- works
-- the to_mytimestamp(varchar) function is called
但是在我的情况下,我无法更改查询,因为它们已在某些代码中定义,而这些代码不应再被更改。
有没有办法让我确保在执行上面的INSERT语句时调用to_mytimestamp(varchar)
函数(不必附加::varchar
)?
非常感谢!
编辑:
以下是提到的功能(根据需要将text
替换为varchar
或char
中的to_mytimestamp()
:
CREATE OR REPLACE FUNCTION to_mytimestamp(t text)
RETURNS mytimestamp AS
$BODY$
declare
ts mytimestamp;
offs text;
matches text[];
begin
offs = substr(t, length(t) - 5, 6);
matches = regexp_matches(offs, '[+-][0-9.:]*', 'g');
offs = split_part(matches[1], ':', 1)::integer * 3600 + split_part(matches[1], ':', 2)::integer * 60;
ts.t = t::timestamp with time zone;
ts.o = offs;
return ts;
end
$BODY$
LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION to_mytimestamp(t timestamp with time zone)
RETURNS mytimestamp AS
' select $1, extract(timezone from $1) '
LANGUAGE sql;
说明:函数提取utc偏移量并将其存储在单独的值中以便以后重建。
注意:to_mytimestamp(t timestamp with time zone)
存储系统偏移量,而不是假设存储在参数t
中的那个,因为带时区的时间戳实际上并不包含偏移量数据 - 但这与问题:)
答案 0 :(得分:2)
我认为你不能这样做。
当你在postgres中写一个字符串文字'foo'
时,它实际上有一个"未知"类型,而不是文本。因此,您的强制转换功能不匹配,因为类型不同。这就是你能做到的原因:
SELECT '2014-09-11 13:30:12.564+02'::text::mytimestamp;
它将按预期工作。
即使您编写了一个处理unknown
作为参数类型的函数的版本(并首先将其转换为text
),并创建相关的强制转换:
CREATE CAST (unknown AS mytimestamp)
WITH FUNCTION mytimestamp(unknown)
AS IMPLICIT;
Postgres仍会尝试使用原始的复合类型转换功能。实际上,这打破了转换为文本的第一个" path,因为mytimestamp(text)
没有更好的匹配,所以它使用内置函数。
答案 1 :(得分:0)
我无法测试,因为缺少to_mytimestamp()函数。但是,这可能就像这样简单:
CREATE CAST (text AS mytimestamp)
WITH FUNCTION to_mytimestamp(text) AS ASSIGNMENT;
? -g