Sto cercando di ottenere il numero di giorni tra due date diverse, tranne i fine settimana.
Non so come raggiungere questo risultato.
Sto cercando di ottenere il numero di giorni tra due date diverse, tranne i fine settimana.
Non so come raggiungere questo risultato.
Risposte:
Supponendo che per "fine settimana" intendi sabato e domenica , questo può essere ancora più semplice:
SELECT count(*) AS count_days_no_weekend
FROM generate_series(timestamp '2014-01-01'
, timestamp '2014-01-10'
, interval '1 day') the_day
WHERE extract('ISODOW' FROM the_day) < 6;
Non è necessario un livello di subquery aggiuntivo per generate_series()
. SRF (imposta funzioni di ritorno), noto anche come "funzioni di tabella", può essere utilizzato proprio come le tabelle nella FROM
clausola.
Si noti in particolare che generate_series()
include il limite superiore nell'output, purché si adatti un intervallo completo (3 ° parametro). Il limite superiore viene escluso solo se l'ultimo intervallo viene troncato, il che non è il caso dei giorni interi.
Con lo schema ISODOW
per EXTRACT () , le domeniche vengono segnalate come 7
, secondo lo standard ISO. Permette una WHERE
condizione più semplice .
Piuttosto chiama generate_series()
con timestamp
input. Ecco perché:
count(*)
è leggermente più corto e più veloce di count(the_day)
, facendo lo stesso in questo caso.
Per escludere il limite inferiore e / o superiore, aggiungere / sottrarre 1 giorno di conseguenza. In genere, è possibile includere il limite inferiore ed escludere il limite superiore:
SELECT count(*) AS count_days_no_weekend
FROM generate_series(timestamp '2014-01-01'
, timestamp '2014-01-10' - interval '1 day'
, interval '1 day') the_day
WHERE extract('ISODOW' FROM the_day) < 6;
Questo esempio elenca tutte le date tra il 15-12-2013 e il 2014-01-02 (inclusivamente). La seconda colonna indica il giorno della settimana (numericamente, tra 0 e 6). La terza colonna indica se il giorno della settimana è un sabato / domenica o meno (dovrai adattare ciò che consideri un fine settimana) ed è ciò che potrebbe essere usato per contare i giorni della settimana.
select '2013-12-15'::date + i * interval '1 day',
extract('dow' from '2013-12-15'::date + i * interval '1 day') as dow,
case when extract('dow' from '2013-12-15'::date + i * interval '1 day') in (0, 6)
then false
else true end as is_weekday
from generate_series(0, '2014-01-02'::date - '2013-12-15'::date) i
;
Supponendo che un fine settimana sia sabato e domenica, è possibile utilizzare il seguente SQL.
select count(the_day) from
(select generate_series('2014-01-01'::date, '2014-01-10'::date, '1 day') as the_day) days
where extract('dow' from the_day) not in (0,6)
Sostituisci le date con le tue scelte e (0,6) con i giorni della settimana che desideri escludere.
Alcune cose che devi prendere in considerazione: -
Non hai menzionato la versione di PostgreSQL in esecuzione. Funziona su 9.1+ ma dovrebbe funzionare su versioni inferiori.
Le date scelte sono incluse quando si utilizza generate_serie. Quindi, se vuoi giorni tra, aggiungi 1 giorno a ciascuna data.
Ci sono un paio di cose che puoi fare per renderlo più semplice. Il metodo che utilizzerei sarebbe quello di assicurarmi che sia disponibile una tabella di date. Puoi crearne rapidamente uno in questo modo:
CREATE TABLE [dbo].[Dates]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(0,1),
[Date] Date NOT NULL unique,
isWeekend BIT NOT NULL DEFAULT(0)
)
Una volta creata la tabella, dovresti essere in grado di popolarla con i dati della data in modo relativamente rapido.
set datefirst 6 --start date is saturday
INSERT INTO dbo.Dates(Date, isWeekend)
select
Date,
case datepart(weekday,date)
--relies on DateFirst being set to 6
when 2 then 1
when 1 then 1
else 0
end as isWeekend
from (
select
dateadd(day, number - 1, 0) as date
from (
SELECT top 100000 row_number() over (order by o.object_id) as number
FROM sys.objects o
cross join sys.objects b
cross join sys.objects c
)numbers
)data
È quindi possibile scrivere la query come conteggio rapido dei record da questa tabella.
select count(*) as NumberOfWeekDays
from dbo.dates
where isWeekend = 0
and date between '1 Jan 2013' and '31 Dec 2013'
Ti consiglio di creare una funzione da usare ogni volta che vuoi e scrivere di meno; )
Questo codice sopra creerà una funzione sql che conta e restituisce la quantità di giorni del fine settimana (sabato, domenica). Proprio come avrai più flessibilità per usare questa funzione.
CREATE OR REPLACE FUNCTION <YourSchemaNameOptional>.count_full_weekend_days(date, date)
RETURNS bigint AS
$BODY$
select COUNT(MySerie.*) as Qtde
from (select CURRENT_DATE + i as Date, EXTRACT(DOW FROM CURRENT_DATE + i) as DiaDate
from generate_series(date ($1) - CURRENT_DATE, date ($2) - CURRENT_DATE ) i) as MySerie
WHERE MySerie.DiaDate in (6,0);
$BODY$
LANGUAGE 'SQL' IMMUTABLE STRICT;
Successivamente, è possibile utilizzare la funzione per restituire solo il numero di giorni del fine settimana in un intervallo. Ecco l'esempio da usare:
SELECT <YourSchemaNameOptional>.count_full_weekend_days('2017-09-11', '2017-09-25') as days; --> RES: 4
Questa selezione deve restituire quattro perché il primo e il secondo giorno sono lunedì e tra loro abbiamo 2 sabati e 2 domeniche.
Ora, per restituire solo giorni lavorativi (senza fine settimana), come vuoi , fai una sottrazione, come nell'esempio seguente:
SELECT (date '2017-09-25' - date '2017-09-11' ) - <YourSchemaName>.count_full_weekend_days('2017-09-11', '2017-09-25'); --> RES: 14 - 4 = 10
-- Returns number of weekdays between two dates
SELECT count(*) as "numbers of days”
FROM generate_series(0, (‘from_date’::date - 'todate'::date)) i
WHERE date_part('dow', 'todate'::date + i) NOT IN (0,6)
-- Returns number of weekdays between two dates
SELECT count(*) as days
FROM generate_series(0, ('2014/04/30'::date - '2014/04/01'::date)) i
WHERE date_part('dow', '2014/04/01'::date + i) NOT IN (0,6)