【问题标题】:Postgres INSERT timestamp with UNION ALL error带有 UNION ALL 错误的 Postgres INSERT 时间戳
【发布时间】:2021-10-20 13:45:21
【问题描述】:

美好的一天!

我需要将数据从 SQL Server 2019 导出/导入到运行 PostgreSQL 13.3 的 AWS RDS

只有几张表中的几百行。
这是我第一次遇到 Postgres,所以我决定将数据简单地编写为“INSERT ... SELECT”,就像我使用 SQL Server 一样...我需要的东西太多了。

我为此使用 DBeaver v21,因为我可以轻松访问源数据库和目标数据库。

我测试成功了:


CREATE TABLE public.invoices (
    invoiceno int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    terminalid int4 NOT NULL,
    invoicedate timestamp NOT NULL,
    description varchar(100) NOT null
    );


INSERT INTO public.invoices(InvoiceNo,TerminalID,InvoiceDate,Description)
SELECT 7 as invoiceno , 5 as terminalid , '2018-10-24 21:29:00' as invoicedate , N'Coffe and cookie' as description 
-- Updated Rows 1
-- No problem here

我用 UNION ALL 编写了其余数据的脚本,就像这样(缩短的示例):

INSERT INTO public.invoices(InvoiceNo,TerminalID,InvoiceDate,Description)
SELECT 7 as invoiceno , 5 as terminalid , '2018-10-24 21:29:00' as invoicedate , N'Coffe and cookie' as description  
UNION ALL
SELECT 1000, 5 , '2018-10-24 21:29:00' , N'Tea and crumpets'

现在我明白了:

SQL Error [42804]: ERROR: column "invoicedate" is of type timestamp without time zone but expression is of type text
  Hint: You will need to rewrite or cast the expression.
  Position: 118

我确实在消息中看到它可以通过 CAST 来“修复”(或重写!).... 但是为什么 Postgres 可以隐式转换 1 行,而 2 行却是不可能的呢?
为什么插入超过 1 行时会失败? - 它清楚地知道如何转换文本 -> 日期 ...
我尝试使用 VALUES、CTE、派生表,但没有成功。
因为我必须花更多时间在 postgres 上——我真的很想了解这里发生了什么。我的语法是否错误(SQL Server 可以正常工作),DBeaver 是否将我的数据弄乱了,等等...?

任何建议将不胜感激。 谢谢

【问题讨论】:

    标签: postgresql import dbeaver


    【解决方案1】:

    '2018-10-24 21:29:00' 是一个字符串值,Postgres 对正确的数据类型比 SQL Server 更挑剔。

    您需要将值指定为适当的时间戳常量,

    timestamp '2018-10-24 21:29:00'
    

    请注意,您可以使用values 子句以更紧凑的形式编写:

    INSERT INTO public.invoices(InvoiceNo,TerminalID,InvoiceDate,Description)
    values 
     (7, 5, timestamp '2018-10-24 21:29:00', 'Coffe and cookie'),
     (1000, 5 , timestamp '2018-10-24 21:29:00' , 'Tea and crumpets');
    

    【讨论】:

      【解决方案2】:

      这种行为的原因是编译顺序。 在您首先使用 VIEW 的情况下,视图中的已编译查询和视图中的列类型(也包括名称)取自“视图”的第一部分(第一个 SELECT 命令)。 所以,你得到的是文本而不是时间戳,它与插入的表类型不匹配。

      MSSQL 编译器更聪明一点:-)。

      在第一个示例中,您有简单的 INSERT INTO ... SELECT .... 并且编译器立即期望时间戳类型-因此,它不会产生任何编译错误(但是当数据不通过自动转换规则时,可能会在执行时出现错误)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-18
        • 2011-07-11
        • 2015-09-03
        • 1970-01-01
        • 1970-01-01
        • 2019-11-08
        • 1970-01-01
        相关资源
        最近更新 更多