列的时间戳类型没有时区,但表达式的类型为字符

时间:2015-09-01 16:30:21

标签: postgresql amazon-redshift

我试图在我尝试在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_timestamp39991231 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

有人可以建议如何解决这个问题吗?

3 个答案:

答案 0 :(得分:7)

Postgres没有将20150901 16:34:02(您的输入)识别为有效的时间/日期格式,因此它假定它是一个字符串。

请使用标准日期格式,最好是ISO-8601。 2015-09-01T16:34:02

SQLFiddle example

答案 1 :(得分:6)

以防万一有人在这里试图从准备好的语句中从groovy或Java中的变量插入postgresql timestamptimestampz并得到相同的错误(就像我做的那样) ,我设法通过将属性stringtype设置为"unspecified"来实现。根据{{​​3}}:

  

指定绑定PreparedStatement参数集时要使用的类型   通过setString()。如果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)。我希望这会有所帮助。

答案 2 :(得分:0)

内部apache-tomcat-9.0.7 / conf / server.xml

在网址末尾添加“ ?stringtype=unspecified”。 例如:

<GlobalNamingResources> 
<Resource name="jdbc/??" auth="Container" type="javax.sql.DataSource"
       ...
       url="jdbc:postgresql://127.0.0.1:5432/Local_DB?stringtype=unspecified"/>
</GlobalNamingResources>