Oracle Spool файл с помощью команды CMD доставляет больше данных, чем ожидалось - PullRequest
0 голосов
/ 26 февраля 2019

У меня есть таблица Oracle "Sales" с идентификатором столбцов, 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 для выполнения файла Spool SQL в режиме CMD для экспорта запроса в CSV.Spoolfile выглядит следующим образом:

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.

когда я выполняю SQL-запрос на сервере Oracle вручную, он выдает правильные данные в '2018-08-25 00: 00: 00'

==> Запрос на CMD в Talend дает 1 часДанных больше, чем ожидалось.

Я действительно не понимаю, почему эта проблема происходит.Мое предположение - временная метка проблемы в запросе "'2018-08-25 00: 00: 00.0000000'".эта метка времени не имеет часового пояса.но я не уверен.

не могли бы вы помочь мне с этой проблемой?Thankyou.

1 Ответ

0 голосов
/ 26 февраля 2019

Кажется, что ручной запрос и запрос Talend выполняются в сеансах с разными часовыми поясами.

Вы не указываете часовой пояс в фиксированном значении, несмотря на наличие 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

Когда вы используете эту простую временную метку по сравнению с вашейВ столбце таблицы, который представляет собой временную метку с часовым поясом, происходит неявное преобразование в часовой пояс сеанса.Вы можете увидеть эффект от его установки вручную:

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

Таким образом, чтобы получить разные данные из двух ваших сеансов, это сравнение использует другое значение, поэтому часовые пояса сеанса должны быть разными.

Простое решение заключается в том, чтобы явно указать часовой пояс в фиксированном значении, но вам нужна другая функция, чтобы избежать ошибки, замеченной ранее;и желательно с регионом вместо смещения, чтобы учесть летнее время (при условии, что значения в вашей таблице также основаны на регионе):

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;

, который получает то же значение.


Я пытался отформатировать часовой пояс в запросе с помощью to_timestamp_tz (substr ('2018-08-25 00: 00: 00.0000000'), 1,25), «ГГГГ-ММ-ДД HH24: mi: ss.ff6 TZH: TZM» в часовом поясе «берлин / европа») в качестве input_timestamp, но все равно дает мне больше данных, чем ожидалось.

Игнорирование нечетного 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;

вы получите (мой сеанс все еще в Нью-Йорке побольший эффект)

TIMESTAMP_WITH_WRONG_TIME        
---------------------------------
2018-08-25 06:00:00.000000 +02:00

Часовой пояс теперь тот, который вы ожидали, но time неверно.У вас та же проблема, что и раньше.Вы по-прежнему конвертируете фиксированное значение без указания часового пояса в метку времени с часовым поясом, поэтому он неявно использует часовой пояс сеанса:

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.Это тот же момент времени, только если смотреть из разных мест / часовых поясов.

Опять же, вам просто нужно указать часовой пояс для фиксированного времени, которое вы используете для сравнения - как timestamp '2018-08-25 00:00:00.0 Europe/Berlin'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...