我如何在提供记录之前和之后获得记录?

How do I get records before and after given one?

提问人:Rod 提问时间:9/15/2010 最后编辑:Ryan KohnRod 更新时间:12/7/2021 访问量:27511

问:

我有以下表格结构:

Id, Message
1, John Doe
2, Jane Smith
3, Error
4, Jane Smith

有没有办法获取错误记录和周围的记录?即查找所有错误以及它们之前和之后的记录。

sql sql-server t-sql

评论

0赞 HLGEM 8/27/2014
首先,定义之前和之后。没有保证的顺序来挑选之前和之后的内容。

答:

6赞 Quassnoi 9/15/2010 #1
WITH    err AS 
        (
        SELECT  TOP 1 *
        FROM    log
        WHERE   message = 'Error'
        ORDER BY
                id
        ),
        p AS
        (
        SELECT  TOP 1 l.*
        FROM    log
        WHERE   id <
                (
                SELECT  id
                FROM    err
                )
        ORDER BY
                id DESC
        )
SELECT  TOP 3 *
FROM    log
WHERE   id >
        (
        SELECT  id
        FROM    p
        )
ORDER BY
        id

评论

1赞 JNK 9/15/2010
+1 - 很好地处理了 ID 列中的间隙,应该运行得很快。
0赞 NimChimpsky 9/15/2010 #2
select id, message from tbl where id in (
    select id from tbl where message = "error"
    union
    select id-1 from tbl where message = "error"
    union
    select id+1 from tbl where message = "error"
    )

评论

3赞 Quassnoi 9/15/2010
如果 s 不是连续的怎么办?id
0赞 NimChimpsky 9/15/2010
这是行不通的;但在给出的例子中,它们是连续的。
1赞 Quassnoi 9/15/2010
@Nim:你也可以硬编码 , , —— 举个例子!:)234
5赞 Quassnoi 9/15/2010
@Nim:从表中删除记录也很常见。
1赞 Quassnoi 9/15/2010
@JNK:它既不会失败也不会返回:它只会返回比预期更少的记录。NULLS
3赞 Philip Kelley 9/15/2010 #3

调整这个例程来挑选你的目标。

DECLARE @TargetId  int
SET @TargetId = 3

select *
 from LogTable
 where Id in (--  "before"
              select max(Id)
               from LogTable
               where Id < @TargetId
              --  target
              union all select @TargetId
              --  "after"
              union all select min(Id)
               from LogTable
               where Id > @TargetId)
17赞 Martin Smith 9/15/2010 #4
;WITH numberedlogtable AS
(
SELECT Id,Message, 
ROW_NUMBER() OVER (ORDER BY ID) AS RN
 FROM logtable
)

SELECT Id,Message
FROM numberedlogtable
WHERE RN IN (SELECT RN+i
             FROM numberedlogtable
             CROSS JOIN (SELECT -1 AS i UNION ALL SELECT 0 UNION ALL SELECT 1) n
             WHERE Message='Error')

评论

1赞 Rod 9/15/2010
你能用通俗易懂的语言解释一下吗?如果没有,不用担心。无论如何,谢谢。
3赞 Martin Smith 9/15/2010
因为我们不知道你的 id 序列是否可以有间隙,所以我曾经得到一个没有间隙的保证序列。此查询被放入一个公用表表达式中,并使用了两次。一次查找有错误的行号。然后将其交叉连接到小表上,因此对于找到的每个行号,我们都会得到 3 个行号(previous、target 和 next)。确定感兴趣的行号后,将重新插入原始查询以检索相应的记录。ROW_NUMBER()
0赞 MAK 12/12/2019
@MartinSmith,你能帮帮我解决这个问题吗:stackoverflow.com/questions/59299909/......
1赞 sumek 9/15/2010 #5
;WITH Logs AS 
(
SELECT ROW_NUMBER() OVER (ORDER BY id), id, message as rownum  FROM LogTable lt
) 
SELECT curr.id, prev.id, next.id 
FROM Logs curr 
LEFT OUTER JOIN Logs prev ON curr.rownum+1=prev.rownum 
RIGHT OUTER JOIN Logs next ON curr.rownum-1=next.rownum 
WHERE curr.message = 'Error'
1赞 The King 9/15/2010 #6
select id,messag from 
 (Select (Row_Number() over (order by ID)) as RNO, * from #Temp) as A, 
 (select SubRNO-1 as A, 
  SubRNO as B, 
  SubRNO+1 as C 
  from (Select (Row_Number() over (order by ID)) as SubRNO, * from #Temp) as C
  where messag = 'Error') as B
  where A.RNO = B.A or A.RNO = B.B or A.RNO = B.C
0赞 Matthew Rideout 12/7/2021 #7

在目标之前和之后获得固定的行数

使用 UNION 进行简单、高性能的查询(我发现上面选定的答案 WITH 查询速度非常慢)

当您知道给定记录的 ID 或特定标识符,并且想要在该记录之前之后选择固定数量的记录时,这是 WITH top selected 答案的高性能替代方法。需要 ID 的数字字段,或者可以按升序/降序排序的日期之类的字段。

例:您希望选择记录特定错误之前和之后的 10 条记录,您知道错误 ID,并且可以按日期或 ID 排序。

以下查询获取(包括)上面的 1 个结果、标识的记录本身以及下面的 1 条记录。在 UNION 之后,结果将按降序再次排序。

SELECT q.*
FROM(
    SELECT TOP 2
        id, content
    FROM
        the_table
    WHERE 
        id >= [ID]
    ORDER BY id ASC
    UNION
    SELECT TOP 1
        id, content
    FROM
        the_table
    WHERE 
        id < [ID]
    ORDER BY id DESC
) q
ORDER BY q.id DESC