Selecione COUNT de dias entre duas datas, exceto finais de semana


9

Estou tentando obter o número de dias entre duas datas diferentes, exceto nos finais de semana.

Não sei como alcançar esse resultado.


11
Por favor, poste sua estrutura de tabela para referência. Fins de semana significa SAT e SUN?
Abdul Manaf

Respostas:


10

Supondo que por "fim de semana" você queira dizer sábado e domingo , isso pode ser ainda mais simples:

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;
  • Você não precisa de um nível de subconsulta extra para generate_series(). SRF (funções de retorno de conjunto), também conhecidas como "funções de tabela", podem ser usadas como as tabelas da FROMcláusula.

  • Observe em particular que generate_series() inclui o limite superior na saída, desde que um intervalo completo (terceiro parâmetro) seja adequado. O limite superior será excluído apenas se o último intervalo for truncado, o que não acontece com dias inteiros.

  • Com o padrão ISODOWpara EXTRACT () , os domingos são relatados como 7, de acordo com o padrão ISO. Permite uma WHEREcondição mais simples .

  • Em vez disso, ligue generate_series()com a timestampentrada. Aqui está o porquê:

  • count(*)é um pouco mais curto e mais rápido do que count(the_day), fazendo o mesmo neste caso.

Para excluir o limite inferior e / ou superior, adicione / subtraia 1 dia de acordo. Normalmente, você pode incluir o limite inferior e excluir o limite 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 exemplo enumera todas as datas entre 15/12/2013 e 02-01-2014 (inclusive). A segunda coluna fornece o dia da semana (numericamente, entre 0 e 6). A terceira coluna marca se o dia da semana é um sábado / domingo ou não (você precisará adaptar o que considera um fim de semana) e é o que poderia ser usado para contar os dias da 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

Supondo que um final de semana seja sábado e domingo, você pode usar o seguinte 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)

Substitua as datas por suas escolhas e (0,6) pelos dias da semana que você deseja excluir.

Algumas coisas que você precisa observar: -

  1. Você não mencionou qual versão do PostgreSQL você está executando. Isso funciona no 9.1+, mas deve funcionar nas versões inferiores.

  2. As datas escolhidas são inclusivas ao usar generate_series. Então, se você quiser dias entre, adicione 1 dia para cada data.


0

Existem algumas coisas que você pode fazer para facilitar isso. O método que eu usaria seria garantir que uma tabela de datas estivesse disponível. Você pode criar rapidamente um assim:

CREATE TABLE [dbo].[Dates]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(0,1),
[Date] Date NOT NULL unique,
isWeekend BIT NOT NULL DEFAULT(0)
)

Depois que a tabela for criada, você poderá preenchê-la com dados de data relativamente rapidamente.

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

Você pode escrever sua consulta como uma contagem rápida de registros desta tabela.

select count(*) as NumberOfWeekDays
from dbo.dates 
where isWeekend = 0
and date between '1 Jan 2013' and '31 Dec 2013'

0

Eu sugiro que você crie uma função para uso sempre que quiser e escreva menos; )

Este código acima criará uma função sql que conta e retorna a quantidade de dias de final de semana (sábado, domingo). Da mesma maneira que você terá mais flexibilidade para usar esta função.

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;

Depois disso, você pode usar a função para retornar apenas o número de dias do final de semana em um intervalo. Aqui está o exemplo a ser usado:

SELECT <YourSchemaNameOptional>.count_full_weekend_days('2017-09-11', '2017-09-25') as days; --> RES: 4

Essa seleção deve retornar quatro, porque o primeiro e o segundo dia são segunda-feira e temos dois sábados e dois domingos entre eles.

Agora, para retornar apenas dias úteis (sem fins de semana), como desejar , basta fazer uma subtração, como no exemplo abaixo:

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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.