Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

SQL mengisi total hari kerja per bulan dikurangi hari libur bank untuk tahun keuangan saat ini

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

Jika Anda melakukan ini selama lebih dari 1 tahun, Anda perlu mengubah baris:

OPTION (MAXRECURSION 366)

Jika tidak, Anda akan mendapatkan kesalahan - Jumlahnya harus lebih tinggi dari jumlah hari yang Anda tanyakan.

EDIT

Saya baru saja menemukan jawaban lama saya ini dan benar-benar tidak menyukainya, ada begitu banyak hal yang sekarang saya anggap sebagai praktik yang buruk, jadi saya akan memperbaiki semua masalah:

  1. Saya tidak menghentikan pernyataan dengan titik koma dengan benar
  2. Menggunakan CTE rekursif untuk membuat daftar tanggal
  3. Tidak menyertakan daftar kolom untuk sisipan
  4. Menggunakan DATENAME untuk menghilangkan akhir pekan, yang merupakan bahasa khusus, jauh lebih baik untuk menetapkan DATEFIRST secara eksplisit dan gunakan DATEPART
  5. Menggunakan LEFT JOIN/IS NULL bukannya NOT EXISTS untuk menghilangkan catatan dari tabel liburan. Dalam SQL Server LEFT JOIN/IS NULL kurang efisien daripada NOT EXISTS

Ini semua adalah hal-hal kecil, tetapi itu adalah hal-hal yang akan saya kritik (setidaknya di kepala saya jika tidak dengan keras) ketika meninjau permintaan orang lain, jadi tidak dapat benar-benar tidak memperbaiki pekerjaan saya sendiri! Menulis ulang kueri akan memberikan.

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;

Sebagai poin terakhir, kueri ini menjadi lebih sederhana dengan tabel kalender yang menyimpan semua tanggal, dan memiliki bendera untuk hari kerja, hari libur, dll, daripada menggunakan tabel hari libur yang hanya menyimpan hari libur.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bisakah saya menggunakan Keanggotaan ASP.NET dengan SQL Server Compact Edition?

  2. Cara Memigrasi Database SQL Server ke Database Azure SQL

  3. Lingkup variabel SQL Server dalam prosedur tersimpan

  4. Dapatkan lembar Excel ke tabel temp menggunakan skrip

  5. Pengidentifikasi multi-bagian tidak dapat diikat