通过 CMD 命令的 Oracle 假脱机文件提供比预期更多的数据
Oracle Spool file via CMD command deliver more Data than expected
我有一个 Oracle Table "Sales",其中包含 ID、Sales、TIMESTAMP 列。数据如下所示:
ID Sales TimeStamp
1 30 2018-08-20 00:00:00.989900 +02:00
1 35 2018-08-21 05:00:00.989900 +02:00
...
1 35 2018-08-27 05:00:00.989900 +02:00
我创建了一个 Talend 作业以在 CMD 模式下执行 SQL 假脱机文件以将查询导出到 csv。假脱机文件如下所示:
alter session set NLS_TIMESTAMP_TZ_FORMAT ='YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM';
alter session set NLS_TIMESTAMP_FORMAT ='YYYY-MM-DD HH24:mi:ss.ff6';
alter session set NLS_DATE_FORMAT ='YYYY-MM-DD';
alter session set NLS_NUMERIC_CHARACTERS ='.,';
spool C:/test.csv
SET ECHO OFF
SET ...
SELECT * FROM Sales where timestamp< to_timestamp('2018-08-25 00:00:00.0000000','YYYY-MM-DD HH24:mi:ss:ff66 TZH:TZM')
当 TalendJob 在 CMD 模式下运行查询时,它为我提供了比预期更多的数据,数据为“2018-08-25 01:00:00”。
当我在 Oracle 服务器上手动执行 SQL 查询时,它会向“2018-08-25 00:00:00”提供正确的数据
==> Talend 上的 CMD 查询给出了比预期多 1 小时的数据。
我真的不明白为什么会出现这个问题。
我的假设是查询“'2018-08-25 00:00:00.0000000'”中的问题时间戳。此时间戳没有时区。但我不确定。
你能帮我解决这个问题吗?
谢谢。
手动查询和Talend查询好像是运行 sessions 不同时区
尽管格式模型中有 TZH:TZM
,但您没有在固定值中指定时区;事实上你不能用 to_timestamp()
:
select to_timestamp('2018-08-25 00:00:00.0000000 +02:00','YYYY-MM-DD HH24:mi:ss:ff6 TZH:TZM')
from dual;
ORA-01821: date format not recognized
因为该函数为您提供了一个简单的时间戳:
alter session set NLS_TIMESTAMP_FORMAT ='YYYY-MM-DD HH24:mi:ss.ff6';
alter session set NLS_TIMESTAMP_TZ_FORMAT ='YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM';
select to_timestamp('2018-08-25 00:00:00.0000000','YYYY-MM-DD HH24:mi:ss:ff6 TZH:TZM')
as plain_timestamp
from dual;
PLAIN_TIMESTAMP
--------------------------
2018-08-25 00:00:00.000000
当您在与 table 列(带时区的时间戳)的比较中使用该纯时间戳时,会隐式转换为 session 时区。您可以通过手动设置看到效果:
alter session set time_zone = 'Europe/London';
select cast(
to_timestamp('2018-08-25 00:00:00.0000000','YYYY-MM-DD HH24:mi:ss:ff6 TZH:TZM')
as timestamp with time zone
) as timestamp_with_session_zone
from dual;
TIMESTAMP_WITH_SESSION_ZONE
---------------------------------
2018-08-25 00:00:00.000000 +01:00
alter session set time_zone = 'America/New_York';
select cast(
to_timestamp('2018-08-25 00:00:00.0000000','YYYY-MM-DD HH24:mi:ss:ff6 TZH:TZM')
as timestamp with time zone
) as timestamp_with_session_zone
from dual;
TIMESTAMP_WITH_SESSION_ZONE
---------------------------------
2018-08-25 00:00:00.000000 -04:00
因此,要从您的两个 session 获取不同的数据,该比较使用不同的值,因此 session 时区必须不同。
简单的解决方法是在您的固定值中明确指定时区,但您需要一个不同的函数来避免前面看到的错误;并且最好使用区域而不是偏移量以允许夏令时(假设 table 中的值也是 region-based):
select to_timestamp_tz('2018-08-25 00:00:00.0000000 Europe/Berlin','YYYY-MM-DD HH24:mi:ss:ff6 TZR')
as timestamp_with_berlin_zone
from dual;
TIMESTAMP_WITH_BERLIN_ZONE
---------------------------------
2018-08-25 00:00:00.000000 +02:00
或者您可以使用时间戳文字:
select timestamp '2018-08-25 00:00:00.0 Europe/Berlin' as timestamp_with_berlin_zone
from dual;
得到相同的值。
i haved tried to format the time zone in the Query with to_timestamp_tz(substr('2018-08-25 00:00:00.0000000'),1,25), 'YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM' at time zone 'berlin/europe') as input_timestamp but it stills gives me more data than expected.
忽略奇数 substr()
,它只是从已经固定的字符串中去掉最后两个零,如果你这样做:
select to_timestamp_tz('2018-08-25 00:00:00.0000000', 'YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM')
at time zone 'Europe/Berlin' as timestamp_with_wrong_time
from dual;
你会得到(我的 session 仍在纽约时间以获得更好的效果)
TIMESTAMP_WITH_WRONG_TIME
---------------------------------
2018-08-25 06:00:00.000000 +02:00
时区现在是您所期望的,但是时间是错误的。你有很多和以前一样的问题。您仍在将没有提供时区的固定值转换为带时区的时间戳,因此它隐含地使用 session 时区:
select to_timestamp_tz('2018-08-25 00:00:00.0000000', 'YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM')
as timestamp_with_wrong_time
from dual;
TIMESTAMP_WITH_WRONG_TIME
---------------------------------
2018-08-25 00:00:00.000000 -04:00
然后 at timezone 'Europe/Berlin'
给出了世界时中完全相同的点 - 纽约午夜,即 04:00 UTC - 但在柏林当地时间,即 06:00 .这是同一时间点,只是从不同的 places/time 区域观看。
同样,您只需指定用于比较的固定时间的时区 - 如 timestamp '2018-08-25 00:00:00.0 Europe/Berlin'
。
我有一个 Oracle Table "Sales",其中包含 ID、Sales、TIMESTAMP 列。数据如下所示:
ID Sales TimeStamp
1 30 2018-08-20 00:00:00.989900 +02:00
1 35 2018-08-21 05:00:00.989900 +02:00
...
1 35 2018-08-27 05:00:00.989900 +02:00
我创建了一个 Talend 作业以在 CMD 模式下执行 SQL 假脱机文件以将查询导出到 csv。假脱机文件如下所示:
alter session set NLS_TIMESTAMP_TZ_FORMAT ='YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM';
alter session set NLS_TIMESTAMP_FORMAT ='YYYY-MM-DD HH24:mi:ss.ff6';
alter session set NLS_DATE_FORMAT ='YYYY-MM-DD';
alter session set NLS_NUMERIC_CHARACTERS ='.,';
spool C:/test.csv
SET ECHO OFF
SET ...
SELECT * FROM Sales where timestamp< to_timestamp('2018-08-25 00:00:00.0000000','YYYY-MM-DD HH24:mi:ss:ff66 TZH:TZM')
当 TalendJob 在 CMD 模式下运行查询时,它为我提供了比预期更多的数据,数据为“2018-08-25 01:00:00”。
当我在 Oracle 服务器上手动执行 SQL 查询时,它会向“2018-08-25 00:00:00”提供正确的数据
==> Talend 上的 CMD 查询给出了比预期多 1 小时的数据。
我真的不明白为什么会出现这个问题。 我的假设是查询“'2018-08-25 00:00:00.0000000'”中的问题时间戳。此时间戳没有时区。但我不确定。
你能帮我解决这个问题吗? 谢谢。
手动查询和Talend查询好像是运行 sessions 不同时区
尽管格式模型中有 TZH:TZM
,但您没有在固定值中指定时区;事实上你不能用 to_timestamp()
:
select to_timestamp('2018-08-25 00:00:00.0000000 +02:00','YYYY-MM-DD HH24:mi:ss:ff6 TZH:TZM')
from dual;
ORA-01821: date format not recognized
因为该函数为您提供了一个简单的时间戳:
alter session set NLS_TIMESTAMP_FORMAT ='YYYY-MM-DD HH24:mi:ss.ff6';
alter session set NLS_TIMESTAMP_TZ_FORMAT ='YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM';
select to_timestamp('2018-08-25 00:00:00.0000000','YYYY-MM-DD HH24:mi:ss:ff6 TZH:TZM')
as plain_timestamp
from dual;
PLAIN_TIMESTAMP
--------------------------
2018-08-25 00:00:00.000000
当您在与 table 列(带时区的时间戳)的比较中使用该纯时间戳时,会隐式转换为 session 时区。您可以通过手动设置看到效果:
alter session set time_zone = 'Europe/London';
select cast(
to_timestamp('2018-08-25 00:00:00.0000000','YYYY-MM-DD HH24:mi:ss:ff6 TZH:TZM')
as timestamp with time zone
) as timestamp_with_session_zone
from dual;
TIMESTAMP_WITH_SESSION_ZONE
---------------------------------
2018-08-25 00:00:00.000000 +01:00
alter session set time_zone = 'America/New_York';
select cast(
to_timestamp('2018-08-25 00:00:00.0000000','YYYY-MM-DD HH24:mi:ss:ff6 TZH:TZM')
as timestamp with time zone
) as timestamp_with_session_zone
from dual;
TIMESTAMP_WITH_SESSION_ZONE
---------------------------------
2018-08-25 00:00:00.000000 -04:00
因此,要从您的两个 session 获取不同的数据,该比较使用不同的值,因此 session 时区必须不同。
简单的解决方法是在您的固定值中明确指定时区,但您需要一个不同的函数来避免前面看到的错误;并且最好使用区域而不是偏移量以允许夏令时(假设 table 中的值也是 region-based):
select to_timestamp_tz('2018-08-25 00:00:00.0000000 Europe/Berlin','YYYY-MM-DD HH24:mi:ss:ff6 TZR')
as timestamp_with_berlin_zone
from dual;
TIMESTAMP_WITH_BERLIN_ZONE
---------------------------------
2018-08-25 00:00:00.000000 +02:00
或者您可以使用时间戳文字:
select timestamp '2018-08-25 00:00:00.0 Europe/Berlin' as timestamp_with_berlin_zone
from dual;
得到相同的值。
i haved tried to format the time zone in the Query with to_timestamp_tz(substr('2018-08-25 00:00:00.0000000'),1,25), 'YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM' at time zone 'berlin/europe') as input_timestamp but it stills gives me more data than expected.
忽略奇数 substr()
,它只是从已经固定的字符串中去掉最后两个零,如果你这样做:
select to_timestamp_tz('2018-08-25 00:00:00.0000000', 'YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM')
at time zone 'Europe/Berlin' as timestamp_with_wrong_time
from dual;
你会得到(我的 session 仍在纽约时间以获得更好的效果)
TIMESTAMP_WITH_WRONG_TIME
---------------------------------
2018-08-25 06:00:00.000000 +02:00
时区现在是您所期望的,但是时间是错误的。你有很多和以前一样的问题。您仍在将没有提供时区的固定值转换为带时区的时间戳,因此它隐含地使用 session 时区:
select to_timestamp_tz('2018-08-25 00:00:00.0000000', 'YYYY-MM-DD HH24:mi:ss.ff6 TZH:TZM')
as timestamp_with_wrong_time
from dual;
TIMESTAMP_WITH_WRONG_TIME
---------------------------------
2018-08-25 00:00:00.000000 -04:00
然后 at timezone 'Europe/Berlin'
给出了世界时中完全相同的点 - 纽约午夜,即 04:00 UTC - 但在柏林当地时间,即 06:00 .这是同一时间点,只是从不同的 places/time 区域观看。
同样,您只需指定用于比较的固定时间的时区 - 如 timestamp '2018-08-25 00:00:00.0 Europe/Berlin'
。