Oracle
 sql >> база данни >  >> RDS >> Oracle

Oracle SQL Date към Long и обратно

Губите твърде много точност в преобразуването си, за да можете да се върнете обратно. Можете да се приближите, като използвате времеви клейма вместо дати.

Първо първоначалната ви заявка губеше напълно времевия компонент:

select to_char(date '1970-01-01'
  + (1432550197431912935 - power(2, 60))/power(2, 44), 'YYYY-MM-DD HH24:MI:SS')
from dual;

2013-07-09 01:13:19

... но дори и с това обратното преобразуване е загубило твърде много:

select ((to_date('2013-07-09 01:13:19','YYYY-MM-DD HH24:MI:SS')
  - date '1970-01-01') * power(2, 44)) + power(2, 60) from dual;

1432550197477589405

Което е по-близо от 1432549301782839296, което имате, но все още е доста далече.

Част от проблема е точността на DATE , което е само към втория. Ако използвате TIMESTAMP вместо това можете да се приближите доста; можете да видите, че стойността, която трябва да имате, се предполага, че е много точна:

select timestamp '1970-01-01 00:00:00'
  + numtodsinterval((1432550197431912935 - power(2, 60))/power(2, 44), 'DAY')
from dual;

2013-07-09 01:13:18.775670462

Обратното преобразуване се усложнява от аритметиката на времевия печат, даваща резултати за интервали, които след това трябва да манипулирате, за да се върнете към число, първо като първоначалния брой дни:

select extract(day from int_val)
  + extract(hour from int_val) / 24
  + extract(minute from int_val) / (24 * 60)
  + extract(second from int_val) / (24 * 60 * 60)
from (
select to_timestamp('2013-07-09 01.13.18.775670462', 'YYYY-MM-DD HH24:MI:SS.FF9')
  - timestamp '1970-01-01 00:00:00' as int_val from dual);

15895.0509117554451620370370370370370371

... и след това с вашата властова манипулация:

select ((extract(day from int_val)
    + extract(hour from int_val) / 24
    + extract(minute from int_val) / (24 * 60)
    + extract(second from int_val) / (24 * 60 * 60))
  * power(2, 44)) + power(2, 60)
as x
from (
select to_timestamp('2013-07-09 01.13.18.775670462', 'YYYY-MM-DD HH24:MI:SS.FF9')
  - timestamp '1970-01-01 00:00:00' as int_val from dual);

1432550197431912935.09988554676148148148

Което е адски близо. Можете да отрежете или закръглите това до най-близкото цяло число.

Само разглеждане на вашите числа и манипулирането на мощността във всяка посока показва, че изглежда е в рамките на прецизността, с която Oracle може да се справи:

select (1432550197431912935 - power(2, 60)) / power(2, 44)
from dual;

15895.050911755445156359201064333319664

select (15895.050911755445156359201064333319664 * power(2, 44)) + power(2, 60)
from dual;

1432550197431912935.000...

Дори и с клеймо за време, вие губите част от това, тъй като тази първа стойност надхвърля 9-цифрената дробна секундна граница. Частта, която представлява дробните секунди - след като отчетете 15895 часа и т.н. - е .0000089776673785814232865555418862 на ден, което е .77567046150943497195839881896768 секунди; клеймото за време закръгля това до .775670462 . Така че никога няма да бъде перфектно.

Това също кара човек да се чуди как се генерира оригиналното число; изглежда малко вероятно, че всъщност представлява време до такава изключителна точност, тъй като е под йоктосекунди . Не е съвсем ясно дали „прецизността“ всъщност е артефакт от това, че се манипулира въз основа на степени на 2, но така или иначе не изглежда много полезно. По-обичайно е да използвате датата на епохата в стил Unix, като броите секунди или понякога милисекунди от датата на епохата, която така или иначе използвате, ако изобщо трябва да се съхранява като число. Този дизайн е... интересен.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORA-01950:няма привилегии в пространството за таблици „USERS“

  2. Как да оптимизирам заявка с 10+ присъединявания?

  3. как да генерирате план за обяснение за цялата съхранена процедура

  4. Какво не е наред с тази заявка FIRST_VALUE?

  5. Динамично създаване и изпълнение на sql команди в Oracle