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
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の変数からtimestamp
またはtimestampz
をpostgresqlに挿入しようとした場合、またはJava準備されたステートメントから取得しようとして同じエラー(私がやったように)、プロパティstringtype
を"unspecified"
。 ドキュメント によると:
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()]
このようにして、(Stringからの)タイムスタンプのタイプはpostgresqlによって正しく推測されます。これがお役に立てば幸いです。
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>