Estoy tratando de obtener el número de días entre dos fechas diferentes, excepto los fines de semana.
No sé cómo lograr este resultado.
Estoy tratando de obtener el número de días entre dos fechas diferentes, excepto los fines de semana.
No sé cómo lograr este resultado.
Respuestas:
Suponiendo que por "fin de semana" te refieres a sábado y domingo , esto puede ser aún más simple:
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;
No necesita un nivel de subconsulta adicional para generate_series()
. SRF (establecer funciones de retorno), también conocido como "funciones de tabla", se puede utilizar como tablas en la FROM
cláusula.
Tenga en cuenta, en particular, que generate_series()
incluye el límite superior en la salida, siempre que se ajuste a un intervalo completo (tercer parámetro). El límite superior solo se excluye si se trunca el último intervalo, que no es el caso con días completos.
Con el patrón ISODOW
EXTRACT () , los domingos se informan de 7
acuerdo con el estándar ISO. Permite una WHERE
condición más simple .
Más bien llamar generate_series()
con timestamp
entrada. Aquí es por qué:
count(*)
es ligeramente más corto y más rápido que count(the_day)
, haciendo lo mismo en este caso.
Para excluir el límite inferior y / o superior, sume / reste 1 día en consecuencia. Por lo general, puede incluir el límite inferior y excluir el límite superior:
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;
Este ejemplo enumera todas las fechas entre 2013-12-15 y 2014-01-02 (inclusive). La segunda columna muestra el día de la semana (numéricamente, entre 0 y 6). La tercera columna marca si el día de la semana es un sábado / domingo o no (tendrá que adaptar lo que considera que es un fin de semana) y es lo que podría usarse para contar los días de la semana.
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
;
Suponiendo que un fin de semana sea sábado y domingo, puede usar el siguiente 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)
Reemplace las fechas con sus elecciones y el (0,6) con los días de la semana que desea excluir.
Algunas cosas que debe tener en cuenta:
No ha mencionado qué versión de PostgreSQL está ejecutando. Esto funciona en 9.1+ pero debería funcionar en versiones inferiores.
Las fechas elegidas son inclusivas cuando se utiliza generate_series. Entonces, si desea días intermedios, agregue 1 día a cada fecha.
Hay algunas cosas que puede hacer para facilitar esto. El método que usaría sería asegurarme de que haya una tabla de fechas disponible. Puede crear uno rápidamente así:
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 vez que se crea la tabla, debería poder rellenarla con datos de fecha relativamente rápido.
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
Luego puede escribir su consulta como un recuento rápido de registros de esta tabla.
select count(*) as NumberOfWeekDays
from dbo.dates
where isWeekend = 0
and date between '1 Jan 2013' and '31 Dec 2013'
Le sugiero que cree una función para usar cuando quiera y escriba menos; )
Este código anterior creará una función sql que contará y devolverá la cantidad de días de fin de semana (sábado, domingo). Justo como tendrá más flexibilidad para usar esta función.
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;
Después de eso, puede usar la función para devolver solo la cantidad de días de fin de semana en un intervalo. Aquí está el ejemplo a usar:
SELECT <YourSchemaNameOptional>.count_full_weekend_days('2017-09-11', '2017-09-25') as days; --> RES: 4
Esta selección debe devolver cuatro porque el primer y el segundo día son lunes, y tenemos 2 sábados y 2 domingos entre ellos.
Ahora, para devolver solo los días hábiles (sin fines de semana), como desee , simplemente reste, como en el ejemplo a continuación:
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)