2017-10-27 81 views
5

Pracuję z Oracle SQL i mam tabelę z 3 kolumnami: Process, Start Date i End Date. Chcę obliczyć czas trwania każdego procesu.Ludzki czytelny upływ czasu między wieloma dniami

użyłem tej kwerendy:

select 
(enddate.date_value - startdate.date_value) as duration 
from dual 

a wynik jest w dniach.

Na przykład: data rozpoczęcia jest 30.3.2016 17:14:53 i data zakończenia jest 8.7.2016 14:51:21

Kiedy używać kwerendy, wynikiem jest 99.90032407407407407407407407407407407407, ale chcę prowadzić tak: 3 months, 7 days, 21 hours, 36 minutes, 28 seconds.

Jak mogę to zrobić?

+0

Jak tylko chcesz jednostek większych niż dni, masz problemy. Musisz wybrać, czy masz zamiar kłamać i mieć standardowe miesiące długości (np. Wszystkie 30 dni), czy też masz sytuację, w której "3 miesiące, 7 dni, ..." mogą przedstawiać różne rzeczywiste okresy czasu, w zależności od dokładności * kiedy * w roku wystąpił okres. Żadne nie jest szczególnie atrakcyjne.Czy na pewno potrzebujesz tego, o co prosisz, i że ci, którzy go proszą, rozumieją tego rodzaju kompromisy? –

+0

@Damien_The_Unbeliever, Zgadzam się z tobą, jeśli chcesz przekonwertować tylko pewną liczbę dni, ale jeśli chcesz, aby trwać okres między 2 datami, nie potrzebujesz stałej liczby dni w miesiącu (np. Wszystkie 30 dni) lub ustalonej liczba dni w roku, spójrz na moją propozycję (jestem pewien, że możemy ją uprościć/zoptymalizować, ale wydaje się, że działa!). – Indent

+0

@Indent - starałem się wskazać, że "3 miesiące, 7 dni, ..." mogą przedstawiać różne okresy czasu, jeśli nie przyjmuje się stałych miesięcy. To znaczy. jest to okres od 1 lutego do 8 maja 2000 r. i oznacza rzeczywisty okres 97 dni. Rok później między tymi samymi datami wynosi 96 dni. I w przykładzie OP reprezentuje 99 dni. –

Odpowiedz

1

Różnica między dwoma wartościami DATE to number przedstawiająca liczbę dni. Wydaje się, że chcesz mieć wartość interval, można to zrobić, używając wartości TIMESTAMP.

select cast(enddate as timestamp) - cast(startdate as timestamp) 
from the_table 

Wynik subtracting a timestamp from a timestamp przerwa.

Formatowanie wartości interval jest jednak dość trudne w Oracle. Zobacz np. format interval with to_char

+0

Właściwie wystarczy rzucić tylko jeden, albo "końcową datę" albo "datę początkową". –

2

Ten kompleks query (specjalnie na dzień !!):

Aby obliczyć prawidłowe Day dodam Month i 12 * Year do pierwotnego terminu.

with dates as(
select 
    sysdate  as d1, 
    sysdate-99.90032407407407407407407407407407407407-365 as d2 
from 
    dual 
), 
dates_parts as (
SELECT 
    d1, 
    d2, 
    EXTRACT(YEAR FROM (d1 - d2) YEAR TO MONTH) as Year, 
    EXTRACT(MONTH FROM (d1 - d2) YEAR TO MONTH) as Month, 
    EXTRACT(DAY FROM (d1 - d2) DAY TO SECOND) as Day, 
    EXTRACT(HOUR FROM cast(d1 as timestamp) - cast(d2 as timestamp)) as Hour, 
    EXTRACT(MINUTE FROM cast(d1 as timestamp) - cast(d2 as timestamp)) as Minute,  
    EXTRACT(SECOND FROM cast(d1 as timestamp) - cast(d2 as timestamp)) as Second 
FROM dates 
) 
select 
    dates_parts.Year, 
    dates_parts.Month, 
    dates_parts.Day, 
    dates_parts.Hour, 
    dates_parts.Minute, 
    dates_parts.Second, 
    EXTRACT(DAY FROM (d1 - ADD_MONTHS(d2,Month+Year*12)) DAY TO SECOND) as Day_Corrected 
from 
    dates_parts 

będzie produkować inny termin udział:

| YEAR | MONTH | DAY | HOUR | MINUTE | SECOND | DAY_CORRECTED | 
|------|-------|-----|------|--------|--------|---------------| 
| 1 |  3 | 464 | 21 |  36 |  28 |    7 | 
1

podstawie mojego poprzedniej odpowiedzi można utworzyć funkcję Oracle sinceHumanReadable:

exemple z https://momentjs.com/docs/#/plugins/preciserange/ ten sam wynik

moment("2014-01-01 12:00:00").preciseDiff("2015-03-04 16:05:06"); 
// 1 year 2 months 3 days 4 hours 5 minutes 6 seconds 

http://sqlfiddle.com/#!4/d6783/1

create or replace FUNCTION sinceHumanReadable(start_date IN date,end_date IN date) 
    RETURN VARCHAR2 
IS result VARCHAR2(255); 

    BEGIN 

    with 
    dates_parts as (
    SELECT 
     EXTRACT(YEAR FROM (end_date - start_date) YEAR TO MONTH) as Year, 
     EXTRACT(MONTH FROM (end_date - start_date) YEAR TO MONTH) as Month,  
     EXTRACT(HOUR FROM cast(end_date as timestamp) - cast(start_date as timestamp)) as Hour, 
     EXTRACT(MINUTE FROM cast(end_date as timestamp) - cast(start_date as timestamp)) as Minute,  
     EXTRACT(SECOND FROM cast(end_date as timestamp) - cast(start_date as timestamp)) as Second 
    FROM dual 
    ), 
    dates_parts_with_day as (
    select   
     Year,Month,Hour,Minute,Second, 
     EXTRACT(DAY FROM (end_date - ADD_MONTHS(start_date,Month+Year*12)) DAY TO SECOND) as Day 
    from dates_parts 
    ) 
    select 
     decode(dates_parts_with_day.Year, 0,'', dates_parts_with_day.Year || ' years ')|| 
     decode(dates_parts_with_day.Month,0,'', dates_parts_with_day.Month || ' months ')|| 
     decode(dates_parts_with_day.Day,0,'', dates_parts_with_day.Day || ' days ')|| 
     decode(dates_parts_with_day.Hour,0,'', dates_parts_with_day.Hour || ' hours ')|| 
     decode(dates_parts_with_day.Minute,0,'', dates_parts_with_day.Minute || ' minutes ')|| 
     dates_parts_with_day.Second || ' seconds' 
    into result 
    from 
     dates_parts_with_day; 

    RETURN(result); 

    END sinceHumanReadable; 
GO 

Zapytanie

with dates as ( 
    select sysdate-99.90032407407407407407407407407407407407 as d1,sysdate as d2 from dual 
    union all 
    select to_date('2016-03-30 17:14:53','yyyy-mm-dd hh24:mi:ss') as d1,to_date('2016-07-08 14:51:21','yyyy-mm-dd hh24:mi:ss') as d2 from dual 
    union all 
    select to_date('2014-01-01 12:00:00','yyyy-mm-dd hh24:mi:ss') as d1,to_date('2015-03-04 16:05:06','yyyy-mm-dd hh24:mi:ss') as d2 from dual 
    union all 
    select sysdate as d1,add_months(sysdate,35) as d2 from dual 
    union all 
    select sysdate as d1,sysdate as d2 from dual 
) 
select 
    d1,d2, 
    sinceHumanReadable(d1,d2) as since 
from 
    dates; 

będzie produkować:

|     D1 |     D2 |            SINCE | 
|----------------------|----------------------|-----------------------------------------------------| 
| 2017-07-19T17:50:00Z | 2017-10-27T15:26:28Z |  3 months 7 days 21 hours 36 minutes 28 seconds | 
| 2016-03-30T17:14:53Z | 2016-07-08T14:51:21Z |  3 months 7 days 21 hours 36 minutes 28 seconds | 
| 2014-01-01T12:00:00Z | 2015-03-04T16:05:06Z | 1 years 2 months 3 days 4 hours 5 minutes 6 seconds | 
| 2017-10-27T15:26:28Z | 2020-09-27T15:26:28Z |       2 years 11 months 0 seconds | 
| 2017-10-27T15:26:28Z | 2017-10-27T15:26:28Z |           0 seconds |