2011-06-07 45 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