2011-04-29 19 views
3

可以說,我有硬TSQL的問題 - 行值多少按順序

date,personid 
1/1/2001 1 
1/2/2001 3 
1/3/2001 2 
1/4/2001 2 
1/5/2001 5 
1/6/2001 5 
1/7/2001 6 

一個表,我要請更新2001年1月2日或2001年1月5日與personid 2,但在我可以更新之前,我必須確保它通過一條規則,說你連續三天都不能有人。 我如何解決這個問題在一個mssql存儲過程?

更新:它也需要解決這一佈局,以及在那裏我會更新2001年1月5日

date,personid 
1/1/2001 1 
1/2/2001 3 
1/3/2001 2 
1/4/2001 2 
1/5/2001 1 
1/6/2001 2 
1/7/2001 2 
1/8/2001 5 
1/9/2001 5 
1/10/2001 6 
+0

請澄清你的問題。您是否在尋找T-SQL部分的幫助或者如何編寫存儲過程?我將假設前者,直到你另有所指。 – dawebber 2011-04-29 19:17:53

+0

這個我不清楚。只有預先知道的人物,你試圖找到一個你可以插入的日期,或者是事先知道的可能日期的列表,並且你需要知道哪個人可以接受這個人物,或者你只是尋找所有可能的personid你可以改變每個日期(單獨),而不違反規則? – ErikE 2012-02-04 00:18:56

回答

2

我認爲date是唯一讓我知道這是不是案子!

DECLARE @basedata TABLE ([date] UNIQUE DATE,personid INT) 
INSERT INTO @basedata 
SELECT GETDATE()+1, 2 union all 
SELECT GETDATE()+2, 3 union all 
SELECT GETDATE()+3, 2 union all 
SELECT GETDATE()+4, 2 union all 
SELECT GETDATE()+5, 5 union all 
SELECT GETDATE()+6, 5 union all 
SELECT GETDATE()+7, 6 


DECLARE @date date = GETDATE()+5 
DECLARE @personid int = 2 


;WITH T AS 
(
SELECT TOP 2 [date],personid 
FROM @basedata 
WHERE [date] < @date 
ORDER BY [date] DESC 
UNION ALL 
SELECT @date, @personid 
UNION ALL 
SELECT TOP 2 [date],personid 
FROM @basedata 
WHERE [date] > @date 
ORDER BY [date] 
),T2 AS 
(
SELECT *, 
     ROW_NUMBER() OVER (ORDER BY [date]) - 
     ROW_NUMBER() OVER (PARTITION BY personid ORDER BY [date]) AS Grp 
FROM T 
) 
SELECT COUNT(*) /*Will return a result if that date/personid 
        would cause a sequence of 3*/ 
FROM T2 
GROUP BY personid,Grp 
HAVING COUNT(*) >=3 
+0

我的答案的第一行說我假設'日期'是唯一的。那麼情況並非如此?在這種情況下你如何處理關係? – 2011-04-29 19:39:15

+0

感謝馬丁。作品完美。 – user713813 2011-04-29 19:43:55

+0

嗨馬丁,我怎麼會得到上面的例子工作的情況下,只檢查一個,而不是連續三個? – user713813 2011-05-06 16:46:43

0
SET @TargetDate = '1/2/2001' 

SELECT @ForwardCount = COUNT(*) FROM table WHERE ([date] BETWEEN @TargetDate AND DATEADD(dd, 2, @TargetDate)) WHERE PersonID = @PersonID 

SELECT @BackwardCount = COUNT(*) FROM table WHERE ([date] BETWEEN @TargetDate AND DATEADD(dd, -2, @TargetDate)) WHERE PersonID = @PersonID 

SELECT @BracketCount = COUNT(*) FROM table WHERE ([date] BETWEEN DATEADD(dd, -1, @TargetDate) AND DATEADD(dd, 1, @TargetDate)) WHERE PersonID = @PersonID 

IF (@ForwardCount < 2) AND (@BackwardCount < 2) AND (@BracketCount < 2) 
BEGIN 
-- Do your update here 
END 
+0

+1這個乾淨的易於使用的答案。 請注意,它缺少關於@personid的約束:每個'SELECT'應該以'WHERE ... AND personid = @ personid'結尾。 – krubo 2011-04-30 02:21:53

+0

@krubo - 這個答案可能看起來更簡單,但它不起作用,你提出的修復也不會使它工作! (你最終會排除其他'personid's,所以可能會錯誤地推斷出錯誤中有3個連續錯誤) – 2011-04-30 11:03:05

+0

謝謝你的krubo。將編輯。 – 2011-05-04 18:35:54

0

還有第三種情況沒有列出,它是日期間的情況。我將它包含在下面的解決方案中。

輸出是

PersonId TrackDate UnallowedBefore UnallowedAfter 
----------- ---------- --------------- -------------- 
2   01/04/2001 01/02/2001  01/05/2001 
5   01/06/2001 01/04/2001  01/07/2001 
6   01/08/2001 01/08/2001  01/08/2001 

USE tempdb 
GO 
IF OBJECT_ID('PersonDates') IS NOT NULL DROP TABLE PersonDates 
CREATE TABLE PersonDates 
(
    PersonId int  NOT NULL, 
    TrackDate datetime NOT NULL 
) 

INSERT INTO PersonDates 
(
    TrackDate, 
    PersonId 
) 
SELECT '1/1/2001', 1 
UNION ALL 
SELECT '1/2/2001', 3 
UNION ALL 
SELECT '1/3/2001', 2 
UNION ALL 
SELECT '1/4/2001', 2 
UNION ALL 
SELECT '1/5/2001', 5 
UNION ALL 
SELECT '1/6/2001', 5 
UNION ALL 
SELECT '1/7/2001', 6 
UNION ALL 
SELECT '1/8/2001', 2 
UNION ALL 
SELECT '1/9/2001', 6 

SELECT 
    P.PersonId, 
    TrackDate = CONVERT(varchar(10), DATEADD(day, 1, P.TrackDate), 101), 
    T.UnallowedBefore, 
    T.UnallowedAfter 
FROM 
    PersonDates P 

    CROSS APPLY 
    (
    SELECT TOP 1 
     UnallowedAfter = CASE 
     WHEN DATEDIFF(day, P.TrackDate, TrackDate) = 1 
     THEN CONVERT(varchar(10), DATEADD(day, 1, TrackDate), 101) 
     ELSE CONVERT(varchar(10), DATEADD(day, -1, TrackDate), 101) 
     END, 
     UnallowedBefore = CASE 
     WHEN DATEDIFF(day, P.TrackDate, TrackDate) = 1 
     THEN CONVERT(varchar(10), DATEADD(day, -2, TrackDate), 101) 
     ELSE CONVERT(varchar(10), DATEADD(day, -1, TrackDate), 101) 
     END 
    FROM 
     PersonDates 
    WHERE 
     PersonId = P.PersonId 
     AND 
     DATEDIFF(day, P.TrackDate, TrackDate) IN (1,2) 
) T 
0

這裏是我的parametrised解決方案:

WITH nearby AS (
    SELECT 
    date, 
    personid = CASE date WHEN @date THEN @personid ELSE personid END 
    FROM atable 
    WHERE date BETWEEN DATEADD(day, [email protected], @date) 
       AND DATEADD(day, @MaxInARow, @date) 
), 
nearbyGroups AS (
    SELECT 
    *, 
    Grp = DATEDIFF(day, 0, date) - 
      ROW_NUMBER() OVER (PARTITION BY personid ORDER BY date) 
    FROM nearby 
) 
UPDATE atable 
SET personid = @personid 
WHERE date = @date 
    AND NOT EXISTS (
    SELECT Grp 
    FROM nearbyGroups 
    GROUP BY Grp 
    HAVING COUNT(*) > @MaxInARow 
) 

@date代表其personid欄應更新的日期。 @personid是要存儲的新值。 @MaxInARow是允許存儲相同personid的行中的最大天數。