SQL compilation error: Expression type does not match column data type, expecting TIMESTAMP_NTZ(9) but got TIMESTAMP_LTZ(9) for column CREATE_DT
SQL compilation error: Expression type does not match column data type, expecting TIMESTAMP_NTZ(9) but got TIMESTAMP_LTZ(9) for column CREATE_DT
问题:用于创建 TABLE...默认...CURRENT_TIMESTAMP()
的正确 DDL 是什么
我有一个 CREATE 或 REPLACE 语句,它对 CREATE_DT 列使用 DEFAULT - 当有人将数据插入 table 时,当前服务器 date/time 应该填充该列
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()
);
当我们从列中检索数据时,我们将使用以下命令将系统 date/time 更改为我们的时区。
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 是什么?我们是否需要在创建语句将时区设置为 NTZ(9) 之前更改 DDL 脚本中的会话?我认为 Snowflake 在不同时区有多个服务器,因此系统时间将取决于服务器所在的位置。
Snowflake 文档说
Returns the current timestamp for the system.
https://docs.snowflake.net/manuals/sql-reference/functions/current_timestamp.html
它没有参数来控制它 returns 的时区。
Snowflake 文档中的此页面暗示了 CONVERT_TIMEZONE(source_tz、target_tz、source_timestamp_ntz)的使用,但如果我们处于不同的时区,则同样取决于DEFAULT 正在执行的服务器我认为这也会失败。
https://docs.snowflake.net/manuals/sql-reference/functions/convert_timezone.html
我认为问题在于 TIMESTAMP
数据类型默认为 TIMESTAMP_NTZ
除非您设置 Parameter TIMESTAMP_TYPE_MAPPING = TIMESTAMP_LTZ
由于 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
答案:为列的 DDL 使用数据类型 TIMESTAMP_LTZ(9) 而不是时间戳(见下文)
为了让 date/time 以您的会话格式返回,它必须存储在 table 中,其中一列定义为本地时区值,然后使用 ALTER SESSION 稍后 select 它。这就是信息模式中的对象存储时间戳的方式 - 数据类型为 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;
问题:用于创建 TABLE...默认...CURRENT_TIMESTAMP()
的正确 DDL 是什么我有一个 CREATE 或 REPLACE 语句,它对 CREATE_DT 列使用 DEFAULT - 当有人将数据插入 table 时,当前服务器 date/time 应该填充该列
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()
);
当我们从列中检索数据时,我们将使用以下命令将系统 date/time 更改为我们的时区。
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 是什么?我们是否需要在创建语句将时区设置为 NTZ(9) 之前更改 DDL 脚本中的会话?我认为 Snowflake 在不同时区有多个服务器,因此系统时间将取决于服务器所在的位置。
Snowflake 文档说
Returns the current timestamp for the system. https://docs.snowflake.net/manuals/sql-reference/functions/current_timestamp.html
它没有参数来控制它 returns 的时区。
Snowflake 文档中的此页面暗示了 CONVERT_TIMEZONE(source_tz、target_tz、source_timestamp_ntz)的使用,但如果我们处于不同的时区,则同样取决于DEFAULT 正在执行的服务器我认为这也会失败。
https://docs.snowflake.net/manuals/sql-reference/functions/convert_timezone.html
我认为问题在于 TIMESTAMP
数据类型默认为 TIMESTAMP_NTZ
除非您设置 Parameter TIMESTAMP_TYPE_MAPPING = TIMESTAMP_LTZ
由于 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
答案:为列的 DDL 使用数据类型 TIMESTAMP_LTZ(9) 而不是时间戳(见下文)
为了让 date/time 以您的会话格式返回,它必须存储在 table 中,其中一列定义为本地时区值,然后使用 ALTER SESSION 稍后 select 它。这就是信息模式中的对象存储时间戳的方式 - 数据类型为 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;