sql >> Database >  >> RDS >> Sqlserver

SQL vult het totale aantal werkdagen per maand minus feestdagen in voor het huidige boekjaar

DECLARE @StartDate DATETIME, @EndDate DATETIME

SELECT  @StartDate = '01/04/2011',
        @EndDate = '31/03/2012'
        
CREATE TABLE #Data (FirstDay DATETIME NOT NULL PRIMARY KEY, WorkingDays INT NOT NULL)

;WITH DaysCTE ([Date]) AS
(   SELECT  @StartDate
    UNION ALL
    SELECT  DATEADD(DAY, 1, [Date])
    FROM    DaysCTE
    WHERE   [Date] <= @Enddate
)

INSERT INTO #Data
SELECT  MIN([Date]),
        COUNT(*) [Day]
FROM    DaysCTE
        LEFT JOIN HolidayTable
            ON [Date] BETWEEN HolStart AND HolEnd
WHERE   HolidayTypeID IS NULL
AND     DATENAME(WEEKDAY, [Date]) NOT IN ('Saturday', 'Sunday')
GROUP BY DATEPART(MONTH, [Date]), DATEPART(YEAR, [Date])
OPTION (MAXRECURSION 366)

DECLARE @Date DATETIME
SET @Date = (SELECT MIN(FirstDay) FROM #Data)

SELECT  Period,
        WorkingDays [Days Available (Minus the Holidays)]
FROM    (   SELECT  DATENAME(MONTH, Firstday) [Period],
                    WorkingDays,
                    0 [SortField],
                    FirstDay
            FROM    #Data
            UNION
            SELECT  DATENAME(MONTH, @Date) + ' - ' + DATENAME(MONTH, Firstday),
                    (   SELECT  SUM(WorkingDays)
                        FROM    #Data b
                        WHERE   b.FirstDay <= a.FirstDay
                    ) [WorkingDays],
                    1 [SortField],
                    FirstDay 
            FROM    #Data a
            WHERE   FirstDay > @Date
        ) data
ORDER BY SortField, FirstDay

DROP TABLE #Data

Als u dit langer dan 1 jaar doet, moet u de regel wijzigen:

OPTION (MAXRECURSION 366)

Anders krijg je een foutmelding - Het aantal moet hoger zijn dan het aantal dagen dat je opvraagt.

BEWERKEN

Ik ben net dit oude antwoord van mij tegengekomen en vind het echt niet leuk, er zijn zoveel dingen die ik nu als een slechte gewoonte beschouw, dus ik ga alle problemen corrigeren:

  1. Ik heb verklaringen niet beëindigd met een puntkomma correct
  2. Een recursieve CTE gebruikt om een ​​lijst met datums te genereren
  3. Heeft de kolomlijst voor een invoeging niet opgenomen
  4. DATENAME gebruikt om weekenden te elimineren, wat taalspecifiek is, veel beter om expliciet DATEFIRST in te stellen en gebruik DATEPART
  5. Gebruikt LEFT JOIN/IS NULL in plaats van NOT EXISTS om records uit de vakantietabel te verwijderen. In SQL Server is LEFT JOIN/IS NULL minder efficiënt dan NOT EXISTS

Dit zijn allemaal kleine dingen, maar het zijn dingen die ik zou bekritiseren (althans in mijn hoofd, zo niet hardop) bij het beoordelen van de vraag van iemand anders, dus ik kan mijn eigen werk niet echt niet corrigeren! Het herschrijven van de query zou opleveren.

SET DATEFIRST 1;

DECLARE @StartDate DATETIME = '20110401',
        @EndDate DATETIME = '20120331';

CREATE TABLE #Data (FirstDay DATETIME NOT NULL PRIMARY KEY, WorkingDays INT NOT NULL);

WITH DaysCTE ([Date]) AS
(   SELECT  TOP (DATEDIFF(DAY, @StartDate, @EndDate) + 1)
            DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @StartDate)
    FROM    sys.all_objects a
)
INSERT INTO #Data (FirstDay, WorkingDays)
SELECT  FirstDay =  MIN([Date]),
        WorkingDays = COUNT(*) 
FROM    DaysCTE d
WHERE   DATEPART(WEEKDAY, [Date]) NOT IN (6, 7)
AND     NOT EXISTS
        (   SELECT  1
            FROM    dbo.HolidayTable ht
            WHERE   d.[Date] BETWEEN ht.HolStart AND ht.HolEnd
        )
GROUP BY DATEPART(MONTH, [Date]), DATEPART(YEAR, [Date]);

DECLARE @Date DATETIME = (SELECT MIN(FirstDay) FROM #Data);

SELECT  Period,
        [Days Available (Minus the Holidays)] = WorkingDays 
FROM    (   SELECT  DATENAME(MONTH, Firstday) [Period],
                    WorkingDays,
                    0 [SortField],
                    FirstDay
            FROM    #Data
            UNION
            SELECT  DATENAME(MONTH, @Date) + ' - ' + DATENAME(MONTH, Firstday),
                    (   SELECT  SUM(WorkingDays)
                        FROM    #Data b
                        WHERE   b.FirstDay <= a.FirstDay
                    ) [WorkingDays],
                    1 [SortField],
                    FirstDay 
            FROM    #Data a
            WHERE   FirstDay > @Date
        ) data
ORDER BY SortField, FirstDay;

DROP TABLE #Data;

Als laatste punt wordt deze query veel eenvoudiger met een kalendertabel die alle datums opslaat en vlaggen heeft voor werkdagen, vakanties, enz., in plaats van een vakantietabel te gebruiken die alleen vakanties opslaat.



  1. PostgreSQL dump Temp-tabel

  2. Oracle Grid Installatie - Ontbrekende pakketten compat-libcap1-1.10 en andere

  3. PHP naar mySQL controleren of gebruiker bestaat

  4. Lege tekenreeks die een nul invoegt, geen null