Você está na página 1de 4

Como calcular dias teis no SQL

Server
29 de julho de 2015 body_of_rays

Ol Pessoal,
Bom dia.
Neste post irei mostrar como realizar diversos clculos com dias teis no
SQL Server, criando uma tabela com todas as informaes j calculadas
e restando apenas realizar alguns SELECTs simples para obter essas
informaes.

Pr-Requisito: Tabela de feriados


Um pr-requisito para esse post, voc j ter criado a tabela de feriados
que eu comentei no post Como criar uma tabela com os feriados
(nacionais, estaduais e mveis) no SQL Server. Essa tabela ser utilizada
para identificar se uma data especfica feriado ou no.

Pr-Requisito: Funes para clculo de dia til


Outro pr-requisito para a nossa tabela, so 3 funes utilizadas para
retornar os dias teis, conforme abaixo:
fncDia_Util_Anterior

1
2 CREATE FUNCTION [dbo].[fncDia_Util_Anterior] ( @Data_Dia DATETIME )
3 RETURNS DATETIME
4 AS
5 BEGIN
6
WHILE (1 = 1)
7
BEGIN
8
9
SET @Data_Dia = @Data_Dia - (CASE DATEPART(WEEKDAY, @Data_Dia) WHEN 1 THE
10
11
IF EXISTS ( SELECT TOP 1 Nr_Dia FROM dbo.Feriado WITH ( NOLOCK ) WHERE Nr
12
( Nr_Ano = 0 OR Nr_Ano = YEAR(@Data_Dia) ) )
13
SET @Data_Dia = @Data_Dia - 1
14
ELSE
15
BREAK
16
17
END
18
19
RETURN CAST(FLOOR(CAST(@Data_Dia AS FLOAT)) AS DATETIME)
20
END

fncProximo_Dia_Util
1
2
3
4
5

CREATE FUNCTION [dbo].[fncProximo_Dia_Util] ( @Data_Dia DATETIME )


RETURNS DATETIME
AS
BEGIN

6
WHILE (1 = 1)
7
BEGIN
8
9
SET @Data_Dia = @Data_Dia + (CASE DATEPART(WEEKDAY, @Data_Dia) WHEN 1 THE
10
11
IF EXISTS ( SELECT TOP 1 Nr_Dia FROM dbo.Feriado WITH ( NOLOCK ) WHERE Nr
12
( Nr_Ano = 0 OR Nr_Ano = YEAR(@Data_Dia) ) )
13
SET @Data_Dia = @Data_Dia + 1
14
ELSE
15
BREAK
16
END
17
18
RETURN CAST(FLOOR(CAST(@Data_Dia AS FLOAT)) AS DATETIME)
19
END

fncDia_Util

1
2 CREATE FUNCTION [dbo].[fncDia_Util] ( @Data_Dia DATETIME )
3 RETURNS BIT
4 AS
5 BEGIN
6
DECLARE @retorno BIT
7
8
IF ( DATEPART(WEEKDAY, @Data_Dia) IN ( 1, 7 ) )
9
SET @retorno = 0
10
ELSE
11
BEGIN
12
13
IF EXISTS ( SELECT TOP 1 Nr_Dia FROM dbo.Feriado WITH ( NOLOCK ) WHERE Nr
14 ( Nr_Ano = 0 OR Nr_Ano = YEAR(@Data_Dia) ) )
15
SET @retorno = 0
16
ELSE
17
SET @retorno = 1
18
19
END
20
21
RETURN @retorno
22
END

Criando a tabela de dias teis


Aps criar todos os pr-requisitos necessrios, vamos criar a nossa
tabela de dias teis.
1 SET LANGUAGE 'Brazilian'
2
3 IF (OBJECT_ID('dbo.Dia_Util') IS NOT NULL) DROP TABLE dbo.Dia_Util
4 CREATE TABLE dbo.Dia_Util (
Dt_Referencia DATETIME,
5
Nr_Dia TINYINT,
6
Nr_Mes TINYINT,
7
Nr_Ano INT,
8
Dt_Dia_Util_Anterior DATETIME,
9
Dt_Proximo_Dia_Util DATETIME,
10
Fl_Dia_Util BIT,
11
Fl_Dia_Util_Incluindo_Sabado BIT,
12
Fl_Feriado BIT,
13
Nr_Dia_Semana TINYINT,
14
Ds_Dia_Semana VARCHAR(13),
15

16
Nr_Semana INT,
17
Nr_Semana_Mes INT,
18
Nr_Dia_Ano INT,
19
Qt_Dias_Uteis_Mes INT NULL,
20
Qt_Dias_Uteis_Ano INT NULL
21 )
22
23 DECLARE @Dt_Inicial DATETIME = '19900101', @Dt_Final DATETIME = '20991231'
24
25 WHILE (@Dt_Inicial <= @Dt_Final)
26 BEGIN
27
INSERT INTO dbo.Dia_Util
28
SELECT
29
@Dt_Inicial AS Dt_Referencia,
30
DATEPART(DAY, @Dt_Inicial) AS Nr_Dia,
31
DATEPART(MONTH, @Dt_Inicial) AS Nr_Mes,
32
DATEPART(YEAR, @Dt_Inicial) AS Nr_Ano,
33
dbo.fncDia_Util_Anterior(DATEADD(DAY, -1, @Dt_Inicial)) AS Dt_Dia_Util_Anteri
34
dbo.fncProximo_Dia_Util(DATEADD(DAY, 1, @Dt_Inicial)) AS Dt_Proximo_Dia_Util,
35
dbo.fncDia_Util(@Dt_Inicial) AS Fl_Dia_Util,
36
(CASE WHEN DATEPART(WEEKDAY, @Dt_Inicial) = 1 OR EXISTS(SELECT TOP 1 Nr_D
37
MONTH(
@Dt_Inicial
) AND Tp_Feriado = '1' AND (Nr_Ano = 0 OR Nr_Ano = YEAR(@Dt_Inici
38
(CASE
WHEN
EXISTS(SELECT TOP 1 Nr_Dia FROM dbo.Feriado WITH(NOLOCK) WHER
39
40 = 0 OR Nr_Ano = YEAR(@Dt_Inicial))) THEN 1 ELSE 0 END) AS Fl_Feriado,
DATEPART(WEEKDAY, @Dt_Inicial) AS Nr_Dia_Semana,
41
DATENAME(WEEKDAY, @Dt_Inicial) AS Ds_Dia_Semana,
42
DATEPART(WEEK, @Dt_Inicial) AS Nr_Semana,
43
DATEPART(WEEK, @Dt_Inicial) - DATEPART(WEEK, @Dt_Inicial - DATEPART(DAY, @Dt
44
DATEPART(DAYOFYEAR, @Dt_Inicial) AS Nr_Dia_Ano,
45
NULL AS Qt_Dias_Uteis_Mes,
46
NULL AS Qt_Dias_Uteis_Ano
47
48
49
SET @Dt_Inicial = DATEADD(DAY, 1, @Dt_Inicial)
50
51
52 END
53
54
55 -- POPULA A QUANTIDADE DE DIAS TEIS AT A DATA
56 DECLARE @Qt_Dias_Uteis_Mes INT, @Qt_Dias_Uteis_Ano INT
57
58 SET @Dt_Inicial = '19900101'
59
60 WHILE (@Dt_Inicial <= @Dt_Final)
61 BEGIN
62
63
SET @Qt_Dias_Uteis_Mes = (SELECT COUNT(*) FROM dbo.Dia_Util WITH(NOLOCK) WHER
64
Nr_Mes = MONTH(@Dt_Inicial))
65
SET @Qt_Dias_Uteis_Ano = (SELECT COUNT(*) FROM dbo.Dia_Util WITH(NOLOCK) WHER
66
67
68
UPDATE
69
A
70
SET
71
Qt_Dias_Uteis_Mes = @Qt_Dias_Uteis_Mes,
72
Qt_Dias_Uteis_Ano = @Qt_Dias_Uteis_Ano
73
FROM
74
dbo.Dia_Util A
75
WHERE
76
Dt_Referencia = @Dt_Inicial

77
78
SET @Dt_Inicial = DATEADD(DAY, 1, @Dt_Inicial)
79
80 END
81
CREATE CLUSTERED INDEX Idx01 ON dbo.Dia_Util(Dt_Referencia)

Com isso, conseguimos a seguinte tabela:

isso a, pessoal!
At o prximo post!