SQL编译错误:表达式类型与列数据类型不匹配,预期为TIMESTAMP_NTZ(9),但列CREATE_DT为TIMESTAMP_LTZ(9)

时间:2019-11-21 17:22:07

标签: create-table snowflake-data-warehouse

问题:创建表...默认... CURRENT_TIMESTAMP()正确使用什么DDL

我有一个CREATE或REPLACE语句,它将DEFAULT用作CREATE_DT列-当有人将数据插入表中时,当前服务器日期/时间应填充该列

CREATE OR REPLACE TABLE "EDW_ADMIN"."ETL_SPROC_LOG" (   
   "ETL_SPROC_LOG_ID" NUMBER IDENTITY NOT NULL, 
   "OBJECT_NAME" VARCHAR2(250 CHAR) NOT NULL, 
   "LOG_ENTRY" VARCHAR2(1000 CHAR) NOT NULL, 
   "DYNAMIC_SQL" VARCHAR2(10000 CHAR) NULL,
   "DURATION" NUMBER NULL,
   "ROWS_AFFECTED" NUMBER NULL,
   "ERROR_CODE" VARCHAR2(200 CHAR) NULL, 
   "ERROR_DESC" VARCHAR2(4000 CHAR) NULL, 
   "CREATE_DT" TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
   "CREATE_USER" VARCHAR2(50) NOT NULL DEFAULT CURRENT_USER()
);

当我们从列中检索数据时,我们将使用以下内容将系统日期/时间更改为我们的时区。

ALTER SESSION SET TIMEZONE = 'AMERICA/NEW_YORK';

当我们像这样执行一个示例插入语句时,会出现错误:

   INSERT INTO edw_admin.ETL_SPROC_LOG (OBJECT_NAME, LOG_ENTRY) VALUES ('OBJ', 'ENTRY1');

SQL compilation error: Expression type does not match column data type, expecting TIMESTAMP_NTZ(9) but got TIMESTAMP_LTZ(9) for column CREATE_DT

用于定义DEFAULT CURRENT_TIMESTAMP()的正确DDL是什么?在create语句将时区设置为NTZ(9)之前,我们是否需要在DDL脚本中更改会话?我认为Snowflake在不同时区具有多个服务器,因此系统时间取决于服务器所在的位置。

雪花文档说

  

返回系统的当前时间戳。   https://docs.snowflake.net/manuals/sql-reference/functions/current_timestamp.html

它没有参数来控制它返回的时区。

Snowflake文档中的此页面暗指使用CONVERT_TIMEZONE(source_tz,target_tz,source_timestamp_ntz),但是同样,如果根据DEFAULT在其上执行的服务器的不同,时区也不同,我会认为这也会失败。 / p>

https://docs.snowflake.net/manuals/sql-reference/functions/convert_timezone.html

2 个答案:

答案 0 :(得分:1)

我认为问题在于,除非您设置Parameter TIMESTAMP_TYPE_MAPPING = TIMESTAMP_LTZ,否则TIMESTAMP数据类型默认为TIMESTAMP_NTZ

由于CURRENT_TIMESTAMP()产生一个TIMESTAMP_LTZ值,因此数据类型不匹配。

这似乎可行:

CREATE OR REPLACE TABLE TM (
  V NUMBER,
  T TIMESTAMP DEFAULT CURRENT_TIMESTAMP::TIMESTAMP
);
INSERT INTO TM(V) VALUES(12345);
SELECT * FROM TM;

V       T
12345   2019-11-21 19:03:57.098

答案 1 :(得分:0)

答案:使用数据类型TIMESTAMP_LTZ(9)代替列DDL的时间戳(请参见下文)

为了使日期/时间恢复为您所使用的会话的格式,必须将其存储在表中,并在该列中定义为“本地时区”值,然后稍后使用ALTER SESSION选择它。这就是信息模式中的对象存储时间戳的方式-数据类型为TIMESTAMP_LTZ(9)。

这是最终的代码和结果

CREATE OR REPLACE TABLE "EDW_ADMIN"."ETL_SPROC_LOG" (   
   "ETL_SPROC_LOG_ID" NUMBER IDENTITY NOT NULL, 
   "OBJECT_NAME" VARCHAR2(250 CHAR) NOT NULL, 
   "LOG_ENTRY" VARCHAR2(1000 CHAR) NOT NULL, 
   "DYNAMIC_SQL" VARCHAR2(10000 CHAR) NULL,
   "DURATION" NUMBER NULL,
   "ROWS_AFFECTED" NUMBER NULL,
   "ERROR_CODE" VARCHAR2(200 CHAR) NULL, 
   "ERROR_DESC" VARCHAR2(4000 CHAR) NULL, 
   "CREATE_DT" TIMESTAMP_LTZ(9) DEFAULT CURRENT_TIMESTAMP(),
   "CREATE_USER" VARCHAR2(50) NOT NULL DEFAULT CURRENT_USER()
);

-- Unit test the new tables identity column and defaults
INSERT INTO edw_admin.ETL_SPROC_LOG (OBJECT_NAME, LOG_ENTRY) VALUES ('OBJ', 'ENTRY1');

ALTER SESSION SET TIMEZONE = 'America/New_York';
select create_dt from etl_sproc_log;
    2019-11-21 15:04:50.108 -0500

ALTER SESSION SET TIMEZONE = 'America/Los_Angeles';
select create_dt from etl_sproc_log;
    2019-11-21 12:04:50.108 -0800

ALTER SESSION SET TIMEZONE = 'GMT';
select create_dt from etl_sproc_log;
    2019-11-21 20:04:50.108 +0000

ALTER SESSION UNSET TIMEZONE;
select create_dt from etl_sproc_log;
    2019-11-21 12:04:50.108 -0800


truncate table edw_admin.etl_sproc_log;