Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

SQL điền tổng số ngày làm việc mỗi tháng trừ đi ngày nghỉ ngân hàng cho năm tài chính hiện tại

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

Nếu bạn làm điều này trong hơn 1 năm, bạn sẽ cần phải thay đổi dòng:

OPTION (MAXRECURSION 366)

Nếu không, bạn sẽ gặp lỗi - Con số cần phải cao hơn số ngày bạn đang truy vấn.

CHỈNH SỬA

Tôi vừa xem qua câu trả lời cũ này của mình và thực sự không thích nó, có rất nhiều điều mà bây giờ tôi coi là thực hành không tốt, vì vậy tôi sẽ sửa lại tất cả các vấn đề:

  1. Tôi đã không chấm dứt các tuyên bố với dấu chấm phẩy đúng
  2. Đã sử dụng CTE đệ quy để tạo danh sách ngày
  3. Không bao gồm danh sách cột cho một phụ trang
  4. Đã sử dụng DATENAME để giảm bớt các ngày cuối tuần, vốn là ngôn ngữ cụ thể, tốt hơn nhiều để đặt DATEFIRST một cách rõ ràng và sử dụng DATEPART
  5. Đã sử dụng LEFT JOIN/IS NULL thay vì NOT EXISTS để loại bỏ các bản ghi khỏi bảng kỳ nghỉ. Trong SQL Server LEFT JOIN / IS NULL kém hiệu quả hơn NOT EXISTS

Tất cả đều là những điều nhỏ nhặt, nhưng chúng là những thứ tôi sẽ phê bình (ít nhất là trong đầu nếu không muốn nói là lớn tiếng) khi xem xét truy vấn của người khác, vì vậy không thể thực sự không sửa chữa tác phẩm của chính mình! Viết lại truy vấn sẽ mang lại.

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;

Cuối cùng, truy vấn này trở nên đơn giản hơn nhiều với bảng lịch lưu trữ tất cả các ngày và có cờ cho ngày làm việc, ngày lễ, v.v. thay vì sử dụng bảng ngày lễ chỉ lưu trữ ngày lễ.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sử dụng dạng xem SQL từ mã khung thực thể Phiên bản đầu tiên 5

  2. Làm cách nào để bỏ danh sách các bảng SQL Server, bỏ qua các ràng buộc?

  3. Ngăn chặn việc chèn các phạm vi ngày chồng chéo bằng cách sử dụng trình kích hoạt SQL

  4. Có thể truyền một tham số để kích hoạt trong cơ sở dữ liệu SQL Server không?

  5. Truyền trực tuyến hình ảnh dựa trên dữ liệu bằng HttpHandler