1

SQL (MSSQL) にまだ慣れていないときにレポート用に書いた古いコードを再検討しています。それは想定されていることを行いますが、最もきれいでも最も効率的でもありません。

以下のダミーコードは、私が現在持っているものを模倣しています。ここでは、過去 5 週間に開かれた契約の数を取得しようとしています。この例では、契約の開始日が特定の週の前または中、終了日が特定の週の最中または後に発生する場合、契約はオープンであると見なされます。

dbo.GetWeekStart(@Date DATETIME, @NumOfWeeks INT, @FirstDayOfWeek CHAR(3)) は、指定された週数の日付に基づいて各週の最初の日を返す関数です。つまり、SELECT * FROM dbo.GetWeekStart('20120719', -2, 'MON') は、2012 年 7 月 19 日より前の 2 つの月曜日を返します。

これをどのように単純化できますか?ループなしでこれを行う人がいると思いますが、私はそれを理解できていません。

DECLARE @RunDate DATETIME,
    @Index INT,
    @RowCount INT,
    @WeekStart DATETIME,
    @WeekEnd DATETIME

DECLARE @Weeks TABLE
(
    WeekNum INT IDENTITY(0,1),
    WeekStart DATETIME,
    WeekEnd DATETIME
)

DECLARE @Output TABLE
(
    WeekStart DATETIME,
    OpenContractCount INT
)

SET @RunDate = GETDATE()

INSERT INTO @Weeks (WeekStart, WeekEnd)
SELECT WeekStart,
DATEADD(ss,-1,DATEADD(ww,1,WeekStart))
FROM dbo.[GetWeekStart](@RunDate, -5, 'MON') 

SET @RowCount = (SELECT COUNT(*) FROM @Weeks)
SET @Index = 0

WHILE @Index < @RowCount
BEGIN
    SET @WeekStart = (SELECT WeekStart FROM @Weeks WHERE WeekNum = @Idx)
    SET @WeekEnd = (SELECT WeekEnd FROM @Weeks WHERE WeekNum = @Idx)

    INSERT INTO @Output (WeekStart, OpenContractCount)
    SELECT @WeekStart,
    COUNT(*)
    FROM Contracts c
    WHERE c.StartDate <= @WeekEnd
    AND ISNULL(c.EndDate, GETDATE()) >= @WeekStart

    SET @Index = @Index + 1
END
SELECT * FROM @Output
4

2 に答える 2

0

これをすばやく実行しましたが、動作するはずです

/*CTE generates Start & End Dates for 5 weeks
Start Date = Sunday of week @ midnight
End Date = Sunday of next week @ midnight
*/
WITH    weeks
      AS ( SELECT   DATEADD(ww, -4,
                            CAST(FLOOR(CAST(GETDATE() - ( DATEPART(dw,
                                                          GETDATE()) - 1 ) AS FLOAT)) AS DATETIME)) AS StartDate
           UNION ALL
           SELECT   DATEADD(wk, 1, StartDate)
           FROM     weeks
           WHERE    DATEADD(wk, 1, StartDate) <= GETDATE()
         )
SELECT  w.StartDate ,
        COUNT(*) AS OpenContracts
FROM    dbo.Contracts c
        LEFT   JOIN weeks w ON c.StartDate < DATEADD(d, 7, w.StartDate)
                               AND ISNULL(c.EndDate, GETDATE()) >= w.StartDate
GROUP BY w.StartDate
于 2012-07-19T15:59:30.433 に答える
0

これがうまくいかない理由はわかりません:

DECLARE @RunDate DATETIME = GETDATE()

SELECT  WeekStart, COUNT(*)
FROM    Contracts c
        INNER JOIN dbo.[GetWeekStart](@RunDate, -5, 'MON') 
            ON c.StartDate < DATEADD(WEEK, 1, WeekStart)
            AND (c.EndDate IS NULL OR c.EndDate >= @WeekStart)
GROUP BY WeekStart

関数内でどのように日付を生成しているのかわかりません.ループ/再帰CTEを使用している場合に備えて、ループ/カーソルなどを使用しないクエリを含めます.

DECLARE @RunDate DATETIME = GETDATE()

-- SET DATEFIRST AS 1 TO ENSURE MONDAY IS THE FIRST DAY OF THE WEEK
-- CHANGE THIS TO SIMULATE CHANGING YOUR WEEKDAY INPUT TO db
SET DATEFIRST 1 

-- SET RUN DATE TO BE THE START OF THE WEEK
SET @RunDate = CAST(DATEADD(DAY, 1 - DATEPART(WEEKDAY, @RunDate), @RunDate) AS DATE)

;WITH Weeks AS
(   SELECT  TOP 5 -- CHANGE THIS TO CHANGE THE WEEKS TO RUN
            DATEADD(WEEK, 1 - ROW_NUMBER() OVER(ORDER BY Object_ID), @RunDate) [WeekStart]
    FROM    sys.All_Objects
)
SELECT  WeekStart, COUNT(*)
FROM    Contracts c
        INNER JOIN Weeks
            ON c.StartDate < DATEADD(WEEK, 1, WeekStart)
            AND (c.EndDate IS NULL OR c.EndDate >= @WeekStart)
GROUP BY WeekStart
于 2012-07-19T16:58:23.540 に答える