2011-06-07 48 views
5

最近的記錄 - 向下滾動,我添加了一個編輯 -SQL服務器 - 選擇從一組類似記錄

因此,這裏是我的方案。每次有人對某些數據進行更改時,我都有一張表格。原因是我們需要能夠審計所有的變化。

但是,我只想檢索用戶所做的一系列編輯的最新記錄。

所以我們可以說有三個用戶,用戶A,B和C

用戶A 10度的變化(10個條目中的表格)。 用戶B使得5改變 用戶A 3個更多的變化 用戶C使2改變

我想回去是什麼: 最近的2所記錄的是C語言創建的 最近的3個記錄是A創建 最近的5個記錄是b創建 最近的10條記錄是A創建

,共4行,我回去

這裏是我試過了,但問題是,當LastUpd時RowNum不會回到1 atedBy變化:

WITH cte AS 
(
    SELECT 
     [LastUpdatedOn] 
     ,[LastUpdatedBy] 
     ,ROW_NUMBER() OVER(PARTITION BY [LastUpdatedBy] ORDER BY [LastUpdatedOn] DESC) [RowNum] 
    FROM [HistoricalTable] 
)   
SELECT 
    [LastUpdatedOn] 
    ,[LastUpdatedBy] 
    ,RowNum 
FROM cte 
--WHERE RowNum = 1 
ORDER BY [LastUpdatedOn] DESC; 

而這裏的輸出我得到(**星號代表的行,我想回去)

LastUpdatedOn LastUpdatedBy RowNum 
**2011-06-07 13:07:26.917 629 1** 
2011-06-07 12:57:53.700 629 2 
2011-06-07 12:57:44.387 629 3 
2011-06-07 12:57:34.913 629 4 
2011-06-07 12:57:25.040 629 5 
2011-06-07 12:57:19.927 629 6 
2011-06-07 12:55:17.460 629 7 
2011-06-07 12:55:12.287 629 8 
2011-06-07 12:30:34.377 629 9 
**2011-06-07 11:54:05.727 4 1** 
**2011-06-07 11:50:02.723 629 10** (If this number went back to 1, my query would have worked fine) 
2011-06-07 11:26:43.053 629 11 
2011-06-07 10:54:32.867 629 12 
2011-06-07 10:46:32.107 629 13 
2011-06-07 10:40:52.937 629 14 
**2011-06-07 10:39:50.880 3 1** 

---------------- ---編輯--------------------

所以我想出了一個解決方案,但它不是很優雅,不知道我是否喜歡它,但它的伎倆。這可能會讓你更好地理解我想要完成的事情。

DECLARE @temp AS TABLE(LastUpdatedOn datetime, LastUpdatedBy int null, RowNum int); 

DECLARE @newTable AS TABLE(LastUpdatedOn datetime, LastUpdatedBy int null); 

DECLARE @lastUserId int = 0; 

INSERT INTO @temp 
SELECT 
    [LastUpdatedOn] 
    ,[LastUpdatedBy] 
    ,ROW_NUMBER() OVER(ORDER BY [LastUpdatedOn] DESC) [RowNum] 
    FROM [HistoricalTable] 

DECLARE @totalRecords int; 
SELECT @totalRecords = COUNT(*) FROM @temp; 
DECLARE @counter int = 0; 
WHILE @counter <= @totalRecords BEGIN 
    SET @counter = @counter + 1; 

    INSERT INTO @newTable 
    SELECT LastUpdatedOn, LastUpdatedBy 
    FROM @temp 
    WHERE RowNum = @counter AND (@lastUserId != LastUpdatedBy OR (LastUpdatedBy IS NULL)); 

    SELECT @lastUserId = LastUpdatedBy FROM @temp WHERE RowNum = @counter;  
END 

SELECT * FROM @newTable; 

而返回的數據:

LastUpdatedOn LastUpdatedBy 
2011-06-07 13:07:26.917 629 
2011-06-07 11:54:05.727 4 
2011-06-07 11:50:02.723 629 
2011-06-07 10:39:50.880 3 
+0

此查詢(WHERE RowNum = 1未註釋)確實可以爲您提供所需的結果...由於您按用戶對結果集進行分區,然後根據日期對數據集進行排序,因此您應該得到最新的最新記錄當您通過RowNum = 1篩選記錄時,每個用戶都可以再次驗證一次嗎? – Chandu 2011-06-07 19:38:13

+0

在你的例子中,A做了10次改變,然後A做了3次更改。您的代碼將返回A所做的最新更改。但是你的問題說你需要兩行A的更改。第一組A變更與第二組變更有何區別? – 8kb 2011-06-07 19:44:56

+0

@Cyber​​nate - 是的,它會篩選記錄,如果我取消註釋,但不完全正確。如果你看到我的數據輸出,你會看到它從用戶629到用戶4的位置,然後再到629。再次進入629的時候,RowNum會選擇10而不是1,然後我就不會得到我需要的記錄。 – Makotosan 2011-06-07 20:02:00

回答

4
;with cte as 
(
    select *, 
    row_number() over(order by LastUpdatedOn) as rn 
    from HistoricalTable 
) 
select C1.LastUpdatedOn, 
     C1.LastUpdatedBy 
from cte as C1 
    left outer join cte as C2 
    on C1.rn = C2.rn-1 
where C1.LastUpdatedBy <> coalesce(C2.LastUpdatedBy, 0) 

通過LastUpdatedOn創建的每一行順序的行編號和連接到下一行,並且如果LastUpdatedBy改變比較。當心。它是得到最後一行,並且0需要是一些不用作LastUpdatedBy的整數值。

+0

是的!這看起來確實有竅門!它給了我適當的數據。標記爲答案。 – Makotosan 2011-06-07 22:05:38

+1

簡直無法相信我錯過了這樣一個簡單的解決方案,只需將以前的記錄與您的連接條款進行比較即可。謝謝! – Makotosan 2011-06-07 22:11:51

0

這是完全未經測試,但它可能會形成一個工作方案的基礎:

SELECT 
    [Outer].[LastUpdatedOn], 
    [Outer].[LastUpdatedBy] 
FROM [HistoricalTable] AS [Outer] 
WHERE NOT EXISTS 
(
    SELECT * 
    FROM [HistoricalTable] AS [Middle] 
    WHERE [Middle].[LastUpdatedBy] = [Outer].[LastUpdatedBy] 
     AND [Middle].[LastUpdatedOn] > [Outer].[LastUpdatedOn] 
     AND [Middle].[LastUpdatedOn] <= ISNULL(
     (
      SELECT 
       MIN([Inner].[LastUpdatedOn]) 
      FROM [HistoricalTable] AS [Inner] 
      WHERE [Inner].[LastUpdatedBy] != [Outer].[LastUpdatedBy] 
       AND [Inner].[LastUpdatedOn] > [Outer].[LastUpdatedOn] 
     ), [Middle].[LastUpdatedOn]) 
) 

即使這種方法的工作原理,在性能可能會很糟糕,假設你不僅僅有少數幾行。

對於表格中的每一行,確保同一用戶在上下文行和比鏈接到不同用戶的上下文行更早的最早行之間不存在任何其他行。

2

不知道我是否在你的問題中丟失了某些東西,但是下面的SQL沒有回答這個問題?

declare @HistoricalTable table (LastUpdatedOn datetime, LastUpdatedBy int); 

insert into @HistoricalTable (LastUpdatedOn, LastUpdatedBy) values 
('2011-06-07 13:07:26.917', 629),('2011-06-07 12:57:53.700', 629), 
('2011-06-07 12:57:44.387', 629),('2011-06-07 12:57:34.913', 629), 
('2011-06-07 12:57:25.040', 629),('2011-06-07 12:57:19.927', 629), 
('2011-06-07 12:55:17.460', 629),('2011-06-07 12:55:12.287', 629), 
('2011-06-07 12:30:34.377', 629),('2011-06-07 11:54:05.727', 4), 
('2011-06-07 11:50:02.723', 629),('2011-06-07 11:26:43.053', 629), 
('2011-06-07 10:54:32.867', 629),('2011-06-07 10:46:32.107', 629), 
('2011-06-07 10:40:52.937', 629),('2011-06-07 10:39:50.880', 3); 

select 
latest.* 
from 
(
select *, rank() over (partition by LastUpdatedBy order by LastUpdatedOn desc) as UpdateRank 
    from @HistoricalTable 
) latest 
where 
latest.UpdateRank = 1 
order by 
latest.LastUpdatedBy; 

LastUpdatedOn   LastUpdatedBy UpdateRank 
2011-06-07 10:39:50.880   3   1 
2011-06-07 11:54:05.727   4   1 
2011-06-07 13:07:26.917   629   1 
+0

不完全,因爲用戶629的編輯被用戶4的編輯中斷,我應該有2結果LastUpdatedBy = 629 – Makotosan 2011-06-07 22:06:43

+0

你去 - 必須錯過你的問題或測試數據或東西的東西:P,但我認爲這是「但是,我只想檢索用戶所做的一系列編輯的最新記錄。「那扔我 – 2011-06-07 22:37:59

1

今天早上它讓我很震驚,這是一個島嶼問題。這裏是我的解決方案:

CREATE TABLE #tmp (
LastUpdatedBy INT, 
LastUpdatedOn DATETIME 
) 

INSERT INTO #tmp 
     (LastUpdatedOn, LastUpdatedBy) 
VALUES ('2011-06-07 13:07:26.917', 629), 
     ('2011-06-07 12:57:53.700', 629), 
     ('2011-06-07 12:57:44.387', 629), 
     ('2011-06-07 12:57:34.913', 629), 
     ('2011-06-07 12:57:25.040', 629), 
     ('2011-06-07 12:57:19.927', 629), 
     ('2011-06-07 12:55:17.460', 629), 
     ('2011-06-07 12:55:12.287', 629), 
     ('2011-06-07 12:30:34.377', 629), 
     ('2011-06-07 11:54:05.727', 4), 
     ('2011-06-07 11:50:02.723', 629), 
     ('2011-06-07 11:26:43.053', 629), 
     ('2011-06-07 10:54:32.867', 629), 
     ('2011-06-07 10:46:32.107', 629), 
     ('2011-06-07 10:40:52.937', 629), 
     ('2011-06-07 10:39:50.880', 3) ; 

WITH cte 
      AS (SELECT [LastUpdatedOn], 
         [LastUpdatedBy], 
         ROW_NUMBER() OVER (PARTITION BY [LastUpdatedBy] ORDER BY [LastUpdatedOn] DESC) - ROW_NUMBER() OVER (ORDER BY [LastUpdatedOn] DESC) AS [Island] 
       FROM  #tmp 
      ), 
     cte2 
      AS (SELECT *, 
         ROW_NUMBER() OVER (PARTITION BY [Island] ORDER BY [LastUpdatedOn] DESC) AS [rn] 
       FROM  cte 
      ) 
    SELECT [LastUpdatedOn], 
      [LastUpdatedBy] 
    FROM cte2 
    WHERE [rn] = 1 
    ORDER BY [LastUpdatedOn] DESC ; 

的「絕招」這裏要注意,如果你跟蹤ROW_NUMBER兩個分區中,爲一整套,兩者之間的差異將在分區的改變而改變。

+0

好的解決方案,以及!給出正確的輸出。 +1 – Makotosan 2011-06-09 04:41:00