Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Perbandingan tanggal Oracle rusak karena DST

Untuk menghindari kesalahan ini, pertimbangkan untuk menggunakan ekspresi eksplisit dalam klausa where ke jenis stempel waktu (stempel waktu tanpa zona waktu), dengan cara ini:

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

Atau Anda dapat secara eksplisit mengatur zona waktu sesi, misalnya '-05:00' - untuk waktu standar New York (musim dingin),
menggunakan ALTER SESSION time_zone = '-05:00' , atau dengan menyetel variabel lingkungan ORA_SDTZ di semua lingkungan klien,
lihat tautan ini untuk detailnya:http://docs.Oracle.com/cd/E11882_01/server.112/e10729/ch4datetime.htm#NLSPG263

Tapi itu juga tergantung pada apa yang sebenarnya disimpan di kolom stempel waktu di tabel, misalnya stempel waktu apa 2014-07-01 15:00:00 sebenarnya mewakili, apakah ini "waktu musim dingin" atau "waktu musim panas"?

CURRENT_TIMESTAMP fungsi mengembalikan nilai tipe data TIMESTAMP WITH TIME ZONE
lihat tautan ini:http://docs.Oracle.com/cd/B19306_01/server.102/b14200/functions037.htm

Sementara membandingkan cap waktu dan tanggal, Oracle secara implisit mengonversi data ke tipe data yang lebih tepat menggunakan zona waktu sesi !
Lihat tautan ini --> http://docs.Oracle.com/cd/E11882_01/server.112/e10729/ch4datetime.htm#NLSPG251

Dalam kasus khusus kami, Oracle mengeluarkan timestamp kolom ke timestamp with time zone type.

Oracle menentukan zona waktu sesi dari lingkungan klien.
Anda dapat menentukan zona waktu sesi saat ini menggunakan kueri ini:

select sessiontimezone from dual;

Misalnya di PC saya (Menang 7), ketika opsi ""Sesuaikan jam secara otomatis untuk Waktu Musim Panas" dicentang, kueri ini kembali (di bawah SQLDeveloper):

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


Ketika saya menghapus centang opsi ini di Windows dan kemudian restart SQLDeveloper, itu memberikan:

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

Zona waktu sesi sebelumnya adalah zona waktu dengan nama wilayah, di mana Oracle menggunakan aturan Waktu Musim Panas untuk wilayah ini dalam penghitungan tanggal:

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       


Zona waktu terakhir menggunakan offset tetap "+01:00" (selalu "Winter time"), dan Oracle tidak menerapkan aturan DST apa pun untuk itu, ia hanya menambahkan offset tetap.

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  

Harap dicatat, demi rasa ingin tahu, bahwa Y hasil di atas mewakili dua waktu yang berbeda !!!
014-05-29 01:30:00 EUROPE/BELGRADE tidak sama dengan:2014-05-29 01:30:00 +01:00

tetapi sebenarnya ini:
014-05-29 01:30:00 EUROPE/BELGRADE sama dengan:2014-05-29 01:30:00 +02:00

Hal di atas hanya untuk membuat Anda menyadari betapa sederhananya "penghapusan centang kotak" dapat memengaruhi kueri Anda, dan di mana harus menggali alasan ketika pengguna mengeluh "kueri ini berfungsi dengan baik di bulan Januari, tetapi memberi hasil yang salah pada bulan Juli".

Dan masih pada topik ORA-01878 - katakanlah sesi saya adalah EUROPE/Warsaw dan tabel saya berisi stempel waktu ini (tanpa zona waktu)

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

Perhatikan bahwa di wilayah saya perubahan DST, pada tahun 2014, terjadi pada tanggal 30 Maret pukul 2:00 pagi
Ini berarti bahwa pada tanggal 30 Maret, pukul 2:00 malam, saya harus bangun dan mengalihkan jam tangan saya. maju dari 2:00 ke 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 tahu, bahwa stempel waktu ini tidak valid di wilayah saya menurut aturan DST, karena tidak ada waktu 2:30 pada 30 Maret - jam 2:00 jam dipindahkan ke 3:00, dan tidak ada waktu 2:30. Oleh karena itu Oracle melempar kesalahan ORA-01878.

Namun kueri ini berfungsi dengan baik:

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 

Dan inilah alasan kesalahan ini - tabel Anda berisi stempel waktu seperti 2014-03-09 2:30 atau lebih (untuk New York, di mana pergeseran DST terjadi pada 9 Maret dan 2 November), dan Oracle tidak tahu cara mengonversinya dari stempel waktu (tanpa TZ) ke stempel waktu dengan TZ.

Pertanyaan terakhir - mengapa kueri dengan >= tidak berfungsi, tetapi kueri dengan <= berfungsi dengan baik ?

Mereka berfungsi/tidak berfungsi, karena SQLDeveloper hanya mengembalikan 50 baris pertama (mungkin 100 ? Tergantung pada pengaturan). Kueri tidak membaca seluruh tabel, kueri berhenti saat 50(100) baris pertama diambil.
Ubah kueri "berfungsi", misalnya:

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

Ini memaksa kueri untuk membaca semua baris dalam tabel, dan kesalahan akan muncul, saya yakin 100%.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle SQL:Gunakan urutan dalam insert dengan Select Statement

  2. Kueri dua tabel dari skema yang berbeda

  3. Bagaimana cara membuat database baru setelah awalnya menginstal database Oracle 11g Express Edition?

  4. Penanganan BLOB Oracle jdbc yang terlalu rumit

  5. Apa alasan/kegunaannya adalah menggunakan kata kunci ENABLE dalam pernyataan basis data Oracle