views:

86

answers:

6

Thanks everyone for the feedback. This is a favorite.

Hi All,

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

Is there a way to get the error record and the surrounding records? Find all Errors and the record before and after them.

Thanks,

rod.

+1  A: 
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
Quassnoi
+1 - Deals with gaps in ID column very well and should run pretty quick.
JNK
A: 
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"
    )
NimChimpsky
What if `id` s are not consecutive?
Quassnoi
it will not work; but in the example given they are consecutive.
NimChimpsky
@Nim: you could just as well hardcode `2`, `3`, `4` — in example they are! :)
Quassnoi
hardly, I am assuming its an auto increment as they are common
NimChimpsky
@Nim: deleting records from a table is common too.
Quassnoi
having a requirement where the "before and after" refers specifically to the id is also common too. I think we could go for ages discussing the merits, it aint the greatest bit of code ever written I will admit that. But it might work, and it is very simple.
NimChimpsky
@Nim: in this set: `(2, 5, 8)`, `2` is before `5` and `8` is after `5`.
Quassnoi
And ? If that was the question I would have given a different answer. The question gave an example of consecutive numbers, so I answered it.
NimChimpsky
@Nim: simple it is indeed. But merits? work?
Quassnoi
sheesh, you don't like it already. Vote me down if you like.
NimChimpsky
-1 - As soon as you have non-consecutive ids your query will fail or return nulls.
JNK
@JNK: it will neither fail nor return `NULLS`: it will just return less records than expected.
Quassnoi
A: 

Adapt this routine to pick out your target.

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)
Philip Kelley
+1  A: 
;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')
Martin Smith
could you please explain in layman's terms? if not, no worries. Thanks anyway.
rod
Because we don't know whether or not your id sequence can have gaps I used `ROW_NUMBER()` to get a guaranteed sequence with no gaps. This query is put into a common table expression and used twice. Once to find the row numbers with errors. This is then cross joined onto the small table so for each row number found we get 3 row numbers (previous, target and next). Once the row numbers of interest are determined that gets plugged back into the original query to retrieve the corresponding records.
Martin Smith
A: 
;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=prev.rownum 
WHERE curr.message = 'Error'
sumek
A: 
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
The King