Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Porównanie daty Oracle zepsute z powodu czasu letniego

Aby uniknąć tego błędu, rozważ użycie jawnego rzutowania wyrażenia w klauzuli WHERE na typ znacznika czasu (znacznik czasu bez strefy czasowej), w ten sposób:

select * 
from MY_TABLE T
where T.MY_TIMESTAMP >= cast(CURRENT_TIMESTAMP - interval '1' hour As timestamp );

Alternatywnie możesz jawnie ustawić strefę czasową sesji na, na przykład „-05:00” – dla standardowego (zimowego) czasu w Nowym Jorku,
używając ALTER SESSION time_zone = '-05:00' , lub ustawiając zmienną środowiskową ORA_SDTZ we wszystkich środowiskach klienta,
zobacz ten link, aby uzyskać szczegółowe informacje:http://docs.oracle.com/cd/E11882_01/server.112/e10729/ch4datetime.htm#NLSPG263

Ale zależy to również od tego, naprawdę jest przechowywany w kolumnie sygnatury czasowej w tabeli, na przykład sygnatura czasowa 2014-07-01 15:00:00 reprezentuje w rzeczywistości, czy jest to „czas zimowy” czy „czas letni”?

CURRENT_TIMESTAMP funkcja zwraca wartość typu danych TIMESTAMP WITH TIME STREFA
zobacz ten link:http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions037.htm

Podczas porównując znaczniki czasu i daty, Oracle pośrednio konwertuje dane na bardziej precyzyjny typ danych przy użyciu strefy czasowej sesji!
Zobacz ten link --> http://docs.oracle.com/cd/E11882_01/server.112/e10729/ch4datetime.htm#NLSPG251

W naszym konkretnym przypadku Oracle rzutuje timestamp kolumna do timestamp with time zone type.

Oracle określa strefę czasową sesji ze środowiska klienta.
Możesz określić bieżącą strefę czasową sesji za pomocą tego zapytania:

select sessiontimezone from dual;

Na przykład na moim komputerze (Win 7), gdy zaznaczona jest opcja „Automatycznie dostosuj zegar do czasu letniego”, to zapytanie zwraca (w SQLDeveloper):

SESSIONTIMEZONE                                                           
---------------
Europe/Belgrade 


Gdy odznaczę tę opcję w systemie Windows, a następnie ponownie uruchomię SQLDeveloper, otrzymamy:

SESSIONTIMEZONE                                                           
---------------
+01:00     

Poprzednia strefa czasowa sesji to strefa czasowa z nazwą regionu, dla której Oracle używa reguł czasu letniego dla tego regionu w obliczeniach dat:

alter session set time_zone = 'Europe/Belgrade';
select cast( timestamp '2014-01-29 01:30:00' as timestamp with time zone ) As x,
       cast( timestamp '2014-05-29 01:30:00' as timestamp with time zone ) As y
from dual;

session SET altered.
X                            Y                          
---------------------------- ----------------------------
2014-01-29 01:30:00 EUROPE/B 2014-05-29 01:30:00 EUROPE/B 
ELGRADE                      ELGRADE       


Ta ostatnia strefa czasowa używa stałego przesunięcia „+01:00” (zawsze „czasu zimowego”), a Oracle nie stosuje dla niej żadnych reguł czasu letniego, po prostu dodaje stałe przesunięcie.

alter session set time_zone = '+01:00';
select cast( timestamp '2014-01-29 01:30:00' as timestamp with time zone ) As x,
       cast( timestamp '2014-05-29 01:30:00' as timestamp with time zone ) As y
from dual;

session SET altered.
X                            Y                          
---------------------------- ----------------------------
2014-01-29 01:30:00 +01:00   2014-05-29 01:30:00 +01:00  

Zwróć uwagę, dla ciekawości, że Y powyższe wyniki reprezentują dwa różne czasy !!!
014-05-29 01:30:00 EUROPE/BELGRADE to nie to samo co:2014-05-29 01:30:00 +01:00

ale tak naprawdę to:
014-05-29 01:30:00 EUROPE/BELGRADE jest równe:2014-05-29 01:30:00 +02:00

Powyższe informacje mają tylko uświadomić, jak proste „odznaczenie pola” może wpłynąć na Twoje zapytania i gdzie szukać przyczyny, gdy użytkownicy narzekają, że „to zapytanie działało dobrze w styczniu, ale dało błędne wyniki w lipcu”.

I nadal w temacie ORA-01878 - powiedzmy, że moja sesja to EUROPE/Warsaw a moja tabela zawiera ten znacznik czasu (bez strefy czasowej)

'TIMESTAMP'2014-03-30 2:30:00'

Zauważ, że w moim regionie zmiana czasu letniego w 2014 roku następuje 30 marca o godzinie 2:00.
Oznacza to po prostu, że 30 marca o godzinie 2:00 w nocy muszę się obudzić i przestawić zegarek dalej od 2:00 do 3:00;)

alter session set time_zone = 'Europe/Warsaw';
select cast( TIMESTAMP'2014-03-30 2:30:00' as timestamp with time zone ) As x
from dual;

SQL Error: ORA-01878: podane pole nie zostało znalezione w dacie-godzinie ani w interwale
01878. 00000 -  "specified field not found in datetime or interval"
*Cause:    The specified field was not found in the datetime or interval.
*Action:   Make sure that the specified field is in the datetime or interval.

Oracle wie, że ten znacznik czasu nie jest ważny w moim regionie zgodnie z regułami czasu letniego, ponieważ w dniu 30 marca nie ma godziny 2:30 - o godzinie 2:00 zegar zostaje przesunięty na 3:00, a godziny 2:30 nie ma. Dlatego Oracle zgłasza błąd ORA-01878.

Jednak to zapytanie działa idealnie:

alter session set time_zone = '+01:00';
select cast( TIMESTAMP'2014-03-30 2:30:00' as timestamp with time zone ) As x
from dual;

session SET altered.
X                          
----------------------------
2014-03-30 02:30:00 +01:00 

I to jest przyczyna tego błędu - Twoja tabela zawiera znaczniki czasu, takie jak 2014-03-09 2:30 lub tak (w przypadku Nowego Jorku, gdzie zmiany czasu letniego występują 9 marca i 2 listopada), a Oracle nie wie, jak przekonwertować je ze znacznika czasu (bez TZ) na znacznik czasu z TZ.

Ostatnie pytanie - dlaczego zapytanie z >= nie działa, ale zapytanie z <= działa dobrze ?

Działają/nie działają, ponieważ SQLDeveloper zwraca tylko pierwsze 50 wierszy (może 100 ? To zależy od ustawień). Zapytanie nie czyta całej tabeli, zatrzymuje się po pobraniu pierwszych 50 (100) wierszy.
Zmień „działające” zapytanie na, na przykład:

select sum( EXTRACT(HOUR from MY_TIMESTAMP) ) from MY_TABLE 
where MY_TIMESTAMP <= (CURRENT_TIMESTAMP - interval '1' hour );

To zmusi zapytanie do odczytania wszystkich wierszy w tabeli i pojawi się błąd, jestem w 100% pewien.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Verify_queryable_inventory zwróciło ORA-20008:Przekroczono limit czasu

  2. Obsługa wielu języków w 11i/R12

  3. Wydajność SUBSTR na CLOB

  4. Uruchom Oracle Forms jako samodzielny bez przeglądarki

  5. to jest błąd ORA-12154:TNS:nie można rozwiązać podanego identyfikatora połączenia?