我试图在我试图在Redshift上实现SCD2时插入记录但是出错了。
目标表的DDL是
CREATE TABLE ditemp.ts_scd2_test (
id INT
,md5 CHAR(32)
,record_id BIGINT IDENTITY
,from_timestamp TIMESTAMP
,to_timestamp TIMESTAMP
,file_id BIGINT
,party_id BIGINT
)
这是insert语句:
INSERT
INTO ditemp.TS_SCD2_TEST(id, md5, from_timestamp, to_timestamp)
SELECT TS_SCD2_TEST_STAGING.id
,TS_SCD2_TEST_STAGING.md5
,from_timestamp
,to_timestamp
FROM (
SELECT '20150901 16:34:02' AS from_timestamp
,CASE
WHEN last_record IS NULL
THEN '20150901 16:34:02'
ELSE '39991231 11:11:11.000'
END AS to_timestamp
,CASE
WHEN rownum != 1
AND atom.id IS NOT NULL
THEN 1
WHEN atom.id IS NULL
THEN 1
ELSE 0
END AS transfer
,stage.*
FROM (
SELECT id
FROM ditemp.TS_SCD2_TEST_STAGING
WHERE file_id = 2
GROUP BY id
HAVING count(*) > 1
) AS scd2_count_ge_1
INNER JOIN (
SELECT row_number() OVER (
PARTITION BY id ORDER BY record_id
) AS rownum
,stage.*
FROM ditemp.TS_SCD2_TEST_STAGING AS stage
WHERE file_id IN (2)
) AS stage
ON (scd2_count_ge_1.id = stage.id)
LEFT JOIN (
SELECT max(rownum) AS last_record
,id
FROM (
SELECT row_number() OVER (
PARTITION BY id ORDER BY record_id
) AS rownum
,stage.*
FROM ditemp.TS_SCD2_TEST_STAGING AS stage
)
GROUP BY id
) AS last_record
ON (
stage.id = last_record.id
AND stage.rownum = last_record.last_record
)
LEFT JOIN ditemp.TS_SCD2_TEST AS atom
ON (
stage.id = atom.id
AND stage.md5 = atom.md5
AND atom.to_timestamp > '20150901 16:34:02'
)
) AS TS_SCD2_TEST_STAGING
WHERE transfer = 1
为了简短起见,我试图将20150901 16:34:02
插入from_timestamp
和39991231 11:11:11.000
到to_timestamp
。
得到
ERROR: 42804: column "from_timestamp" is of type timestamp without time zone but expression is of type character varying
任何人都可以建议如何解决这个问题?
Postgres没有将20150901 16:34:02
(您的输入)识别为有效的时间/日期格式,因此它假定它是一个字符串。
请改用标准日期格式,最好是ISO-8601。 2015-09-01T16:34:02
为了防止有人在这里试图从一个准备好的语句中从groovy或Java中的变量插入到postgresql中的timestamp
或timestampz
并得到相同的错误(就像我做的那样),我设法通过设置属性stringtype
来实现到"unspecified"
。根据documentation:
指定绑定通过setString()设置的PreparedStatement参数时要使用的类型。如果stringtype设置为VARCHAR(默认值),则此类参数将作为varchar参数发送到服务器。如果stringtype设置为unspecified,则参数将作为无类型值发送到服务器,服务器将尝试推断适当的类型。如果您的现有应用程序使用setString()来设置实际上是某些其他类型的参数(例如整数),并且您无法更改应用程序以使用适当的方法(如setInt()),则此选项非常有用。
Properties props = [user : "user", password: "password",
driver:"org.postgresql.Driver", stringtype:"unspecified"]
def sql = Sql.newInstance("url", props)
使用此属性集,可以将时间戳作为字符串变量插入,而不会在问题标题中引发错误。例如:
String myTimestamp= Instant.now().toString()
sql.execute("""INSERT INTO MyTable (MyTimestamp) VALUES (?)""",
[myTimestamp.toString()]
这样,postgresql正确推断出时间戳的类型(来自String)。我希望这有帮助。
在apache-tomcat-9.0.7 / conf / server.xml中
将“?stringtype=unspecified
”添加到url地址的末尾。例如:
<GlobalNamingResources>
<Resource name="jdbc/??" auth="Container" type="javax.sql.DataSource"
...
url="jdbc:postgresql://127.0.0.1:5432/Local_DB?stringtype=unspecified"/>
</GlobalNamingResources>