Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

So sánh ngày Oracle bị hỏng do DST

Để tránh lỗi này, hãy xem xét sử dụng kiểu diễn viên rõ ràng của biểu thức trong mệnh đề where thành loại dấu thời gian (dấu thời gian không có múi giờ), theo cách này:

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

Ngoài ra, bạn có thể đặt múi giờ phiên một cách rõ ràng thành, ví dụ:'-05:00' - đối với giờ chuẩn New York (mùa đông),
bằng cách sử dụng ALTER SESSION time_zone = '-05:00' hoặc bằng cách đặt biến môi trường ORA_SDTZ trong tất cả các môi trường của khách hàng,
xem liên kết này để biết chi tiết:http://docs.oracle.com/cd/E11882_01/server.112/e10729/ch4datetime.htm#NLSPG263

Nhưng nó cũng phụ thuộc vào những gì thực sự được lưu trữ trong cột dấu thời gian trong bảng, chẳng hạn như dấu thời gian 2014-07-01 15:00:00 trên thực tế, đó là "giờ mùa đông" hay "giờ mùa hè"?

CURRENT_TIMESTAMP hàm trả về một giá trị của kiểu dữ liệu TIMESTAMP VỚI KHU VỰC THỜI GIAN
xem liên kết này:http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions037.htm

Trong khi so sánh dấu thời gian và ngày tháng, Oracle chuyển đổi ngầm dữ liệu sang kiểu dữ liệu chính xác hơn bằng cách sử dụng múi giờ phiên!
Xem liên kết này -> http://docs.oracle.com/cd/E11882_01/server.112/e10729/ch4datetime.htm#NLSPG251

Trong trường hợp cụ thể của chúng tôi, Oracle sử dụng timestamp vào cột timestamp with time zone loại.

Oracle xác định múi giờ phiên từ môi trường máy khách.
Bạn có thể xác định múi giờ phiên hiện tại bằng cách sử dụng truy vấn sau:

select sessiontimezone from dual;

Ví dụ:trên PC của tôi (Win 7), khi tùy chọn "" Tự động điều chỉnh đồng hồ cho Giờ tiết kiệm ánh sáng ban ngày "được chọn, truy vấn này trả về (trong SQLDeveloper):

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


Khi tôi bỏ chọn tùy chọn này trong Windows và sau đó khởi động lại SQLDeveloper, nó sẽ cho:

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

Múi giờ của phiên trước đây là múi giờ có tên vùng mà Oracle sử dụng quy tắc Giờ tiết kiệm ánh sáng ban ngày cho vùng này trong tính toán ngày:

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       


Múi giờ thứ hai sử dụng độ lệch cố định "+01:00" (luôn là "Giờ mùa đông") và Oracle không áp dụng bất kỳ quy tắc DST nào cho nó, nó chỉ cần thêm khoảng chênh lệch cố định.

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  

Xin lưu ý, vì lợi ích của sự tò mò, rằng Y kết quả ở trên đại diện cho hai thời điểm khác nhau !!!
014-05-29 01:30:00 EUROPE/BELGRADE không giống với:2014-05-29 01:30:00 +01:00

nhưng thực tế là:
014-05-29 01:30:00 EUROPE/BELGRADE bằng:2014-05-29 01:30:00 +02:00

Trên đây chỉ để giúp bạn biết về mức độ đơn giản "bỏ kiểm tra hộp" có thể ảnh hưởng đến các truy vấn của bạn và tìm lý do ở đâu khi người dùng phàn nàn "truy vấn này hoạt động tốt trong tháng 1, nhưng đã sai kết quả vào tháng 7 ”.

Và vẫn là chủ đề về ORA-01878 - giả sử phiên của tôi là EUROPE/Warsaw và bảng của tôi chứa dấu thời gian này (không có múi giờ)

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

Lưu ý rằng ở khu vực của tôi, sự thay đổi DST, vào năm 2014, xảy ra vào ngày 30 tháng 3 lúc 2 giờ sáng.
Điều đó đơn giản có nghĩa là vào ngày 30 tháng 3, lúc 2 giờ đêm, tôi phải thức dậy và thay đổi đồng hồ của mình chuyển tiếp từ 2:00 đến 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 biết rằng dấu thời gian này không hợp lệ trong khu vực của tôi Theo quy tắc của DST, vì không có thời gian 2:30 ngày 30 tháng 3 - lúc 2:00 đồng hồ được chuyển sang 3:00, và không có thời gian 2:30. Do đó, Oracle ném ra lỗi ORA-01878.

Tuy nhiên, truy vấn này hoạt động hoàn toàn tốt:

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 

Và đây là lý do của lỗi này - bảng của bạn chứa các dấu thời gian như 2014-03-09 2:30 hoặc tương tự (đối với New York, nơi các dịch chuyển DST xảy ra vào ngày 9 tháng 3 và ngày 2 tháng 11) và Oracle không biết cách chuyển chúng từ dấu thời gian (không có TZ) sang dấu thời gian có TZ.

Câu hỏi cuối cùng - tại sao lại truy vấn với >= không hoạt động, nhưng truy vấn với <= hoạt động tốt?

Chúng hoạt động / không hoạt động, bởi vì SQLDeveloper chỉ trả về 50 hàng đầu tiên (có thể là 100? Nó phụ thuộc vào cài đặt). Truy vấn không đọc toàn bộ bảng, nó dừng khi 50 (100) hàng đầu tiên được tìm nạp.
Thay đổi truy vấn "đang hoạt động" thành, ví dụ:

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

Điều này buộc truy vấn phải đọc tất cả các hàng trong bảng và lỗi sẽ xuất hiện, tôi chắc chắn 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. Cách nhanh hơn để Chèn, thông qua tập lệnh, trong Oracle?

  2. Lỗi Oracle sau có nghĩa là gì:chỉ mục cột không hợp lệ

  3. Làm thế nào để trả về một mảng từ Java sang PL / SQL?

  4. Hàm BIN_TO_NUM () trong Oracle

  5. bảng hoặc chế độ xem oracle không tồn tại từ bên trong thủ tục được lưu trữ