none
Dias entre alta e baixa temporada RRS feed

  • Pergunta

  • Pessoal,

    Eu tenho a seguinte tabela:

    ID     PeriodoInicial                     PeriodoFinal                 Temporada     

    1 2012-07-01 00:00:00.000 2012-07-31 00:00:00.000 Alta
    2 2012-12-15 00:00:00.000 2012-12-31 00:00:00.000 Alta
    3 2013-01-01 00:00:00.000 2013-01-31 00:00:00.000 Alta
    4 2013-02-09 00:00:00.000 2013-02-12 00:00:00.000 Feriado

    O que eu preciso fazer é dado um periodo saber a qtade de dias que estão em algumas das temporadas acima.

    Por exemplo se o periodo for 01-09-2012 a 15-09-2012 ele retorna 0
    Se for 01-12-2012 a 16-12-2012 ele retorna 2
    Se for 01-02-2013 a 15-02-2013 ele retorna 4

    Nunca implementei este tipo de consulta e to tendo uma certa dificuldade, cheguei a montar esta:

    SELECT  Descricao,
            DATEDIFF(d, '20130201', EffectiveEndDate) AS NumberOfDays
    FROM    (SELECT Descricao,
                    CASE WHEN PeriodoFinal < '20130215' THEN PeriodoFinal
                         ELSE '20130215'
                    END AS EffectiveEndDate
             FROM   CONFTemporada
             WHERE  ([PeriodoFinal] >= '20130201'
                     AND [PeriodoFinal] <= '20130215'
                     AND [PeriodoInicial] <= '20130215'
                    )
                    OR ([PeriodoInicial] <= '20130215'
                        AND [PeriodoInicial] >= '20130201'
                        AND [PeriodoFinal] >= '20130215'
                       )
                    OR ([PeriodoInicial] >= '20130201'
                        AND [PeriodoInicial] <= '20130215'
                        AND [PeriodoFinal] <= '20130215'
                        AND [PeriodoFinal] >= '20130201'
                       )
            ) AS SubSelect
    Mas ele só retorna o total e não os dias dentro dos periodos..


    http://BrunoZP.com.br || http://BrunoZP.com

    quarta-feira, 19 de setembro de 2012 14:59

Respostas

  • Isso não é tão simples fazer pois existem 5 variações possíveis:

      • O período passado como parâmetro se encontra totalmente dentro de um período cadastrado na tabela;
      • A data inicial passada como parâmetro se encontra dentro de um período cadastrado na tabela, mas a data final se encontra fora de um período cadastrado na tabela;
      • A data final passada como parâmetro se encontra dentro de um período cadastrado na tabela, mas a data inicial se encontra fora de um período cadastrado na tabela;
      • Tanto a data inicial quanto a data final passadas como parâmetro se encontram fora de qualquer período cadastrado na tabela, porém, existe um período cadastrado na tabela que compreende o período passado como parâmetro;
      • Tanto a data inicial quanto a data final passadas como parâmetro se encontram fora de qualquer período cadastrado na tabela, e não existe nenhum período cadastrado na tabela que compreenda o período passado como parâmetro.

    Segue exemplo de como contemplar todas estas possibilidades:

    Declare @Tabela Table (ID int Identity, PeriodoInicial Date, PeriodoFinal Date, Temporada VarChar(20))
    Insert Into @Tabela Values
    ('2012-07-01', '2012-07-31', 'Alta'),
    ('2012-12-15', '2012-12-31', 'Alta'),
    ('2013-01-01', '2013-01-31', 'Alta'),
    ('2013-02-09', '2013-02-12', 'Feriado')
    
    Declare @DataInicial Date, @DataFinal Date
    
    Set @DataInicial = '2012-12-20'
    Set @DataFinal   = '2013-02-20'
    
    ;With CTE as
    (
     Select
       Temporada,
       Dias = Case
                When (@DataInicial between PeriodoInicial and PeriodoFinal) and (@DataFinal between PeriodoInicial and PeriodoFinal) then
                  DateDiff(dd, @DataInicial, @DataFinal)
                When (@DataInicial between PeriodoInicial and PeriodoFinal) and (@DataFinal > PeriodoFinal) then
                  DateDiff(dd, @DataInicial, PeriodoFinal)
                When (@DataInicial < PeriodoInicial) and (@DataFinal between PeriodoInicial and PeriodoFinal) then
                  DateDiff(dd, PeriodoInicial, @DataFinal)
                Else
                  DateDiff(dd, PeriodoInicial, PeriodoFinal)
              End
     From
       @Tabela
     Where
       ((@DataInicial between PeriodoInicial and PeriodoFinal) and (@DataFinal between PeriodoInicial and PeriodoFinal)) or
       ((@DataInicial between PeriodoInicial and PeriodoFinal) and (@DataFinal > PeriodoFinal)) or
       ((@DataInicial < PeriodoInicial) and (@DataFinal between PeriodoInicial and PeriodoFinal)) or
       ((PeriodoInicial between @DataInicial and @DataFinal) and (PeriodoFinal between @DataInicial and @DataFinal))
    )
    Select
      Temporada,
      TotalDias = Sum(Dias)
    From
      CTE
    Group by
      Temporada


    Roberson Ferreira - Database Developer
    Acesse: www.robersonferreira.com.br
    Email: contato@robersonferreira.com.br

    Se esta sugestão for útil, por favor, classifique-a como útil.
    Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.

    • Sugerido como Resposta Roberson Ferreira _ quarta-feira, 19 de setembro de 2012 17:26
    • Marcado como Resposta BrunoZP quarta-feira, 19 de setembro de 2012 18:04
    quarta-feira, 19 de setembro de 2012 17:25

Todas as Respostas

  • Bruno veja se esse exemplo te ajuda.

    --declarando uma tabela temporária
    declare @t as table 
    (ID int,
     PeriodoInicial date,
     PeriodoFinal date,
     Temporada    varchar(15)
     )  
    
    --populando a tabela
    insert into @t
    values
    (1,'2012-07-01 00:00:00.000','2012-07-31 00:00:00.000','Alta'),
    (2,'2012-12-15 00:00:00.000','2012-12-31 00:00:00.000','Alta'),
    (3,'2013-01-01 00:00:00.000','2013-01-31 00:00:00.000','Alta'),
    (4,'2013-02-09 00:00:00.000','2013-02-12 00:00:00.000','Feriado')
    
    
    /*
    Por exemplo se o periodo for 01-09-2012 a 15-09-2012 ele retorna 0
    Se for 01-12-2012 a 16-12-2012 ele retorna 2
    Se for 01-02-2013 a 15-02-2013 ele retorna 4
    */
    declare @dtIni as date ,
            @dtFim as date 
    
    --Setando valores aos paramentros
    select  @dtIni = '2012-12-01',
            @dtFim = '2012-12-16'
    
    --Resultado da 1º opção
    select * 
    from @t 
    where  
        PeriodoInicial between @dtIni and @dtFim
    or  PeriodoFinal   between @dtIni and @dtFim
    
    
    
    -- mudando o valor dos parâmentros
    select  @dtIni = '2013-02-01',
            @dtFim = '2013-02-15'
    
    --Resultado da 2º opção
    select * 
    from @t 
    where  
        PeriodoInicial between @dtIni and @dtFim
    or  PeriodoFinal   between @dtIni and @dtFim


    Se a minha ajuda lhe for útil não esqueça de classificar. Att. Leonardo Marcelino

    quarta-feira, 19 de setembro de 2012 17:02
  • Isso não é tão simples fazer pois existem 5 variações possíveis:

      • O período passado como parâmetro se encontra totalmente dentro de um período cadastrado na tabela;
      • A data inicial passada como parâmetro se encontra dentro de um período cadastrado na tabela, mas a data final se encontra fora de um período cadastrado na tabela;
      • A data final passada como parâmetro se encontra dentro de um período cadastrado na tabela, mas a data inicial se encontra fora de um período cadastrado na tabela;
      • Tanto a data inicial quanto a data final passadas como parâmetro se encontram fora de qualquer período cadastrado na tabela, porém, existe um período cadastrado na tabela que compreende o período passado como parâmetro;
      • Tanto a data inicial quanto a data final passadas como parâmetro se encontram fora de qualquer período cadastrado na tabela, e não existe nenhum período cadastrado na tabela que compreenda o período passado como parâmetro.

    Segue exemplo de como contemplar todas estas possibilidades:

    Declare @Tabela Table (ID int Identity, PeriodoInicial Date, PeriodoFinal Date, Temporada VarChar(20))
    Insert Into @Tabela Values
    ('2012-07-01', '2012-07-31', 'Alta'),
    ('2012-12-15', '2012-12-31', 'Alta'),
    ('2013-01-01', '2013-01-31', 'Alta'),
    ('2013-02-09', '2013-02-12', 'Feriado')
    
    Declare @DataInicial Date, @DataFinal Date
    
    Set @DataInicial = '2012-12-20'
    Set @DataFinal   = '2013-02-20'
    
    ;With CTE as
    (
     Select
       Temporada,
       Dias = Case
                When (@DataInicial between PeriodoInicial and PeriodoFinal) and (@DataFinal between PeriodoInicial and PeriodoFinal) then
                  DateDiff(dd, @DataInicial, @DataFinal)
                When (@DataInicial between PeriodoInicial and PeriodoFinal) and (@DataFinal > PeriodoFinal) then
                  DateDiff(dd, @DataInicial, PeriodoFinal)
                When (@DataInicial < PeriodoInicial) and (@DataFinal between PeriodoInicial and PeriodoFinal) then
                  DateDiff(dd, PeriodoInicial, @DataFinal)
                Else
                  DateDiff(dd, PeriodoInicial, PeriodoFinal)
              End
     From
       @Tabela
     Where
       ((@DataInicial between PeriodoInicial and PeriodoFinal) and (@DataFinal between PeriodoInicial and PeriodoFinal)) or
       ((@DataInicial between PeriodoInicial and PeriodoFinal) and (@DataFinal > PeriodoFinal)) or
       ((@DataInicial < PeriodoInicial) and (@DataFinal between PeriodoInicial and PeriodoFinal)) or
       ((PeriodoInicial between @DataInicial and @DataFinal) and (PeriodoFinal between @DataInicial and @DataFinal))
    )
    Select
      Temporada,
      TotalDias = Sum(Dias)
    From
      CTE
    Group by
      Temporada


    Roberson Ferreira - Database Developer
    Acesse: www.robersonferreira.com.br
    Email: contato@robersonferreira.com.br

    Se esta sugestão for útil, por favor, classifique-a como útil.
    Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.

    • Sugerido como Resposta Roberson Ferreira _ quarta-feira, 19 de setembro de 2012 17:26
    • Marcado como Resposta BrunoZP quarta-feira, 19 de setembro de 2012 18:04
    quarta-feira, 19 de setembro de 2012 17:25
  • Bruno depois q entendi melhor a dúvida,

    Segue uma nova sugestão:

    --declarando uma tabela temporária
    declare @t as table 
    (ID int,
     PeriodoInicial date,
     PeriodoFinal date,
     Temporada    varchar(15)
     )  
    
    --populando a tabela
    insert into @t
    values
    (1,'2012-07-01 00:00:00.000','2012-07-31 00:00:00.000','Alta'),
    (2,'2012-12-15 00:00:00.000','2012-12-31 00:00:00.000','Alta'),
    (3,'2013-01-01 00:00:00.000','2013-01-31 00:00:00.000','Alta'),
    (4,'2013-02-09 00:00:00.000','2013-02-12 00:00:00.000','Feriado')
    
    
    -- Declarando parametros de entrada
    declare @dtIni as date ,
            @dtFim as date 
    
    --Setando valores aos paramentros
    select  @dtIni = '2013-02-01',
            @dtFim = '2013-02-15'        
    
    ;with cte_Dias (dia) as 
    (
        select @dtIni
        union all
        select DATEADD(D,1,dia) from cte_Dias where dia<@dtFim
    )
    
    select COUNT(dia) as qtdDia 
    from cte_Dias as c join @t as t on
        c.dia between t.PeriodoInicial and t.PeriodoFinal


    Se a minha ajuda lhe for útil não esqueça de classificar. Att. Leonardo Marcelino

    quarta-feira, 19 de setembro de 2012 17:44
  • Roberson,

    Você foi mais esperto que eu, pensei somente em analisar com base no Período:

    Declare @Tabela Table (ID int Identity, PeriodoInicial Date, PeriodoFinal Date, Temporada VarChar(20))
    Insert Into @Tabela Values
    ('2012-07-01', '2012-07-31', 'Alta'),
    ('2012-12-15', '2012-12-31', 'Alta'),
    ('2013-01-01', '2013-01-31', 'Alta'),
    ('2013-02-09', '2013-02-12', 'Feriado')
    
    Declare @DataInicial Date, @DataFinal Date
    
    Set @DataInicial = '2012-12-01'
    Set @DataFinal   = '2013-02-28'
    
    Select Temporada, CONVERT(VarChar(7),periodoinicial,111)+' até '+CONVERT(VarChar(7),periodofinal,111) As Periodo, 
               DATEDIFF(DD,PeriodoInicial, PeriodoFinal) As Dias from @Tabela
    Where (PeriodoInicial between @DataInicial and @DataFinal) Or
                (PeriodoFinal between @DataInicial and @DataFinal)
    Group By Temporada, PeriodoInicial,PeriodoFinal
    


    Pedro Antonio Galvão Junior [MVP | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados | SorBR.Net | Professor Universitário | MSIT.com]

    quarta-feira, 19 de setembro de 2012 17:59
  • Muito obrigado!

    Só alterei o

    Select
      Temporada,
      TotalDias = Sum(Dias)
    From
      CTE
    Group by
      Temporada

    para

    Select
      Temporada,
      TotalDias = Sum(Dias)+1
    From
      CTE
    Group by
      Temporada

    Pois o ultimo dia também deve ser considerado.


    http://BrunoZP.com.br || http://BrunoZP.com

    quarta-feira, 19 de setembro de 2012 18:06
  • OK. Cheguei a imaginar isso, mas não tinha certeza.

    Roberson Ferreira - Database Developer
    Acesse: www.robersonferreira.com.br
    Email: contato@robersonferreira.com.br

    Se esta sugestão for útil, por favor, classifique-a como útil.
    Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.

    quarta-feira, 19 de setembro de 2012 18:39