web-dev-qa-db-ja.com

列はタイムゾーンのないタイムスタンプ型ですが、式は文字型です

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:02from_timestampに、39991231 11:11:11.000to_timestampに挿入しようとしています。

そして得る

ERROR: 42804: column "from_timestamp" is of type timestamp without time zone but expression is of type character varying

誰もこの問題を解決する方法を提案できますか?

17
user2518751

Postgresは20150901 16:34:02(入力)を有効な時刻/日付形式として認識しないため、文字列であると想定します。

代わりに標準の日付形式、できればISO-8601を使用してください。 2015-09-01T16:34:02

SQLFiddleの例

7
alroc

誰かがここで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によって正しく推測されます。これがお役に立てば幸いです。

7
Jaime Caffarel

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>
0
Gene