sql >> Database teknologi >  >> RDS >> Sqlserver

SQL udfylde samlede arbejdsdage pr. måned minus helligdage for indeværende regnskabsår

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

Hvis du gør dette i mere end 1 år, skal du ændre linjen:

OPTION (MAXRECURSION 366)

Ellers får du en fejlmeddelelse - Antallet skal være højere end det antal dage, du forespørger på.

REDIGER

Jeg er lige stødt på dette gamle svar og kan virkelig ikke lide det, der er så mange ting, som jeg nu anser for dårlig praksis, så jeg vil rette alle problemerne:

  1. Jeg afsluttede ikke udsagn med et semikolon korrekt
  2. Brugte en rekursiv CTE til at generere en liste over datoer
  3. Inkluderede ikke kolonnelisten for en indsættelse
  4. Brugte DATENAME til at eliminere weekender, hvilket er sprogspecifikt, meget bedre at udtrykkeligt angive DATEFIRST og brug DATEPART
  5. Brugte LEFT JOIN/IS NULL i stedet for NOT EXISTS at eliminere poster fra feriebordet. I SQL Server er LEFT JOIN/IS NULL mindre effektiv end IKKE EKSISTERER

Det er alle småting, men det er ting, jeg ville kritisere (i hvert fald i mit hoved, hvis ikke højt), når jeg gennemgår en andens forespørgsel, så jeg kan ikke rigtig lade være med at rette mit eget arbejde! Omskrivning af forespørgslen ville give.

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;

Som et sidste punkt bliver denne forespørgsel meget enklere med en kalendertabel der gemmer alle datoer og har flag for arbejdsdage, helligdage osv. i stedet for at bruge en ferietabel, der kun gemmer helligdage.



  1. Indsæt post i tabel med position uden at opdatere alle posternes positionsfelt

  2. Skift visningsformat for dato- og tidsfelt i MySQL PHP

  3. Opsporing af høje CLR_MANUAL_EVENT-venter

  4. Hvordan opretter man en sikker mysql forberedt erklæring i php?