Seleccione COUNT días entre dos fechas, excepto los fines de semana.


9

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.


1
Publique la estructura de su tabla como referencia. ¿Fin de semana significa SAT y SUN?
Abdul Manaf

Respuestas:


10

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 FROMclá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 ISODOWEXTRACT () , los domingos se informan de 7acuerdo con el estándar ISO. Permite una WHEREcondición más simple .

  • Más bien llamar generate_series()con timestampentrada. 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;

3

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
;

3

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:

  1. No ha mencionado qué versión de PostgreSQL está ejecutando. Esto funciona en 9.1+ pero debería funcionar en versiones inferiores.

  2. Las fechas elegidas son inclusivas cuando se utiliza generate_series. Entonces, si desea días intermedios, agregue 1 día a cada fecha.


0

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'

0

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

-2
-- 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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.