0

I have the following which seems to work perfectly, except that it's always 1 less than the count I need:

DECLARE @start_day DATETIME;
DECLARE @end_day DATETIME;
DECLARE @start_time DATETIME;
DECLARE @end_time DATETIME;

SET @start_day = '2013-06-03';
SET @end_day = '2013-06-07';

PRINT   DATEDIFF(d, @start_day, @end_day)
      - DATEDIFF(wk, @start_day, @end_day) * 2
      - CASE 
            WHEN DATEPART(dw, @start_day) != 7 AND DATEPART(dw, @end_day) = 7 THEN 1 
            WHEN DATEPART(dw, @start_day) = 7 AND DATEPART(dw, @end_day) != 7 THEN -1 
            ELSE 0
        END 

I should be getting

`5` for `2013-06-03` to `2013-06-07` but it's giving me `4`.
`5` for `2013-06-03` to `2013-06-08` but it's giving me `4`.
`5` for `2013-06-03` to `2013-06-09` but it's giving me `4`.
`6` for `2013-06-03` to `2013-06-10` but it's giving me `5`.

So my question is:

How do I get:

`2013-06-03` to `2013-06-07` to equal 5
`2013-06-03` to `2013-06-08` to equal 5
`2013-06-03` to `2013-06-09` to equal 5
`2013-06-03` to `2013-06-10` to equal 6

Please note, adding +1 to the end does not solve the problem!!!

4

3 回答 3

1
Create table foo (
StartDate datetime not null,
EndDate datetime not null
)

insert into foo (StartDate, EndDate) values (N'2013-06-03', N'2013-06-07'),
(N'2013-06-03', N'2013-06-08'),
(N'2013-06-03', N'2013-06-09'),
(N'2013-06-03', N'2013-06-10')

SELECT 
    DATEDIFF(d, StartDate, EndDate)
    + CASE 
        WHEN DATEPART(dw, StartDate) <= 5 THEN 1 
        ELSE 0
        END
    - DATEDIFF(wk, StartDate, EndDate) * 2
    - CASE 
        WHEN DATEPART(dw, StartDate) != 7 AND DATEPART(dw, EndDate) = 7 THEN 1 
        WHEN DATEPART(dw, StartDate) = 7 AND DATEPART(dw, EndDate) != 7 THEN -1 
        ELSE 0
    END 
FROM foo

SqlFiddle

于 2013-06-18T11:31:51.000 回答
0

我宁愿将 COUNT 与计数表一起使用。

SELECT COUNT(*)
FROM dbo.tTally
WHERE n BETWEEN DATEDIFF(dd, 0, @from) AND DATEDIFF(dd, 0, @to)
AND DATEPART(dw, DATEADD(dd, n, 0)) NOT IN (7, 1)

计数表

于 2013-06-18T14:00:10.410 回答
0

如果您想复制 Excel 的NETWORKDAYS,那么我很久以前就写过这个...

CREATE FUNCTION [dbo].[fnNetworkDays]
(
    @date1 SMALLDATETIME,
    @date2 SMALLDATETIME
)
RETURNS INT
AS
BEGIN
    DECLARE @ret INT,
            @dt1 INT,
            @dt2 INT,
            @dt3 INT,
            @neg INT,
            @wks INT,
            @dyo INT,
            @wkd INT,
            @take INT
    --Midnightise the dates
    SELECT @date1 = DATEADD(dd,0, DATEDIFF(dd,0,@date1)), @date2 = DATEADD(dd,0, DATEDIFF(dd,0,@date2))
    --Get integers to make the calcs easier
    SELECT @dt1 = CONVERT(INT,@date1),@dt2 = CONVERT(INT,@date2)

    IF @dt1 > @dt2
        BEGIN
        SET @neg = -1
        SET @dt3 = @dt1
        SET @dt1 = @dt2
        SET @dt2 = @dt3
        END
    ELSE
        SET @neg = 1

    SET @ret = @dt2 - @dt1 + 1
    SET @wks = FLOOR(@ret / 7)
    SET @dyo = @ret % 7
    SET @wkd = @dt1 % 7

    SELECT @take=CASE @wkd
        WHEN 0 THEN CASE WHEN @dyo = 6 THEN 1 ELSE 0 END
        WHEN 6 THEN CASE WHEN @dyo = 1 THEN 1 ELSE 0 END
        ELSE CASE WHEN @dyo = (6 - @wkd) THEN 1 ELSE CASE WHEN @dyo > (6 - @wkd) THEN 2 ELSE 0 END END
    END 

    SELECT @ret =  @neg * (@ret - @wks * 2 - @take) 

    RETURN @ret
END

可能过于复杂,但它的工作原理。

于 2013-06-18T11:30:56.313 回答