(Aside: Why do people in general (Rahul is not the only one, by any stretch of the imagination) omit the name of their table from the question?)
It is very difficult to do in a relational way because it inherently relies on the ordering of data and relational algebra works on (unordered) sets. I take it that we should assume that there is no significance to the DocID column and it cannot be used to help solve the problem.
In the example, you have S003 and S005 and are missing S004. How do we tell that there is a missing value? Presumably, because there is a comparison operation that tells us 'less than', 'equal', 'greater than', and also because there is a difference function that tells us that the gap between S003 and S005 is 2. Let's assume that '>' and friends do the comparison (works here for character strings), and that you can produce a stored procedure webid_diff() which takes two WebID values and returns the difference.
Then, you could write a query such as:
SELECT a.webid, MIN(b.webid) AS min_next
FROM AnonymousTable AS a, AnonymousTable AS b
WHERE a.webid < b.webid
GROUP BY a.webid;
This uses a non-equijoin between the table and itself to find the minimum successor WebID value for each item.
With that as the core, we can then filter the result to select only those rows for which the gap between WebID and Min_Next is more than one. So, I think we get (1st attempt):
SELECT x.webid, y.min_next, webid_diff(x.webid, y.min_next) AS gap
FROM AnonymousTable AS x,
(SELECT a.webid, MIN(b.webid) AS min_next
FROM AnonymousTable AS a, AnonymousTable AS b
WHERE a.webid < b.webid
GROUP BY a.webid
) AS y
WHERE x.webid = y.webid
AND webid_diff(x.webid, y.min_next) > 1;
Is the join at the outer level actually getting us anything useful? I don't think so, so we can remove it, leading to (2nd attempt):
SELECT y.webid, y.min_next, webid_diff(y.webid, y.min_next) AS gap
FROM (SELECT a.webid, MIN(b.webid) AS min_next
FROM AnonymousTable AS a, AnonymousTable AS b
WHERE a.webid < b.webid
GROUP BY a.webid
) AS y
WHERE webid_diff(y.webid, y.min_next) > 1;
This does work. Trying to put the webid_diff() function into the inner query gives me problems - at least the GAP expression would have to be included in the GROUP BY clause, but that then is going to give the wrong answer.
The HAVING clause is used to apply filter conditions to aggregates, so it looks a bit as though the query might be reducible to:
SELECT a.webid, MIN(b.webid) AS min_next, webid_diff(a.webid, b.webid) AS gap
FROM AnonymousTable AS a, AnonymousTable AS b
WHERE a.webid < b.webid
GROUP BY a.webid
HAVING webid_diff(a.webid, b.webid) > 1;
However, this doesn't work (for me, with my DBMS - IBM Informix Dynamic Server) because webid_diff() is not an aggregate.
Here's the code I used for the webid_diff() function (you'd have to adjust to suit the syntax of your DBMS), and the auxilliary webid_num() function:
CREATE FUNCTION webid_num(a CHAR(4)) RETURNING INTEGER;
DEFINE i INTEGER;
LET i = substr(a, 2, 3);
RETURN i;
END FUNCTION;
CREATE FUNCTION webid_diff(a CHAR(4), b CHAR(4)) RETURNING INTEGER;
DEFINE i, j INTEGER;
LET i = webid_num(a);
LET j = webid_num(b);
RETURN (j - i);
END FUNCTION;