English 中文(简体)
Table with identity field: Best SQL query to get Ids of deleted records?
原标题:

I have a table with an identity field. What the best SQL query to get the Ids of all the deleted records from this table?

最佳回答

Left join with a numbers table and grab all the ones where it is null, this uses the built in numbers table but it is better to have your own

example of what the code would look like

create table #bla(id int)

insert #bla values(1)
insert #bla values(2)
insert #bla values(4)
insert #bla values(5)
insert #bla values(9)
insert #bla values(12)



select number from master..spt_values s
left join #bla b on s.number = b.id
where s.type= P 
and s.number < (select MAX(id) from #bla)
and  b.id is null

output

0 3 6 7 8 10 11

See here: How to return all the skipped identity values from a table in SQL Server for some more detail

问题回答

A completely different way to do it is this:

SELECT a.intId, b.intId
FROM MyTable a
    CROSS JOIN MyTable b
WHERE a.intId + 1 < b.intId
    AND NOT EXISTS (
        SELECT NULL FROM MyTable c
        WHERE c.intId > a.intId
            AND c.intId < b.intId
    )

Which will give pairs of IDs between which all the records have been removed.

So if the IDs were (1, 2, 3, 6, 7, 12), it would return (3, 6) and (7, 12).

EDIT:

This is very inefficient if the table is large. The following method is much better:

SELECT g.intStartId, MIN(t.intId) AS intEndId
FROM (
    SELECT intId AS intStartId
    FROM MyTable AS a
    WHERE NOT EXISTS (
        SELECT NULL FROM MyTable AS b
        WHERE b.intId = a.intId + 1
    )
) AS g
    CROSS JOIN MyTable AS t
WHERE t.intId > g.intStartId
GROUP BY g.intStartId

So we first find IDs that mark the start of a gap, and then we find the lowest ID we have greater than each to mark the end of the gap.

You could use a recursive query:

DECLARE @MaxId int
SELECT @MaxId = SELECT IDENT_CURRENT( MyTable );

WITH Ids AS (
    SELECT 1 AS intId
    UNION ALL
    SELECT intId + 1
    FROM Ids
    WHERE intId < @MaxId
)
SELECT intId
FROM Ids AS i
WHERE NOT EXISTS (
    SELECT NULL FROM MyTable AS m
    WHERE m.intId = i.intId
)
OPTION (MAXRECURSION 0)

Though this won t be very efficient if the table is very large.

One option is to create a temporary table/embeddable SQL statement containing all possible IDs (some options are outlined in this article) up to an including the max(identity) of your table.

Then you can left join from this canonical list of values with your table and filter on a null values on the right side.

A query focusing on sequential ID column is not enough. The ID sequence may skip numbers during insert if transaction fails, so if you have ID = (1,3) it does not mean that ID=2 was deleted, it may have been skipped. You have to use something to catch deleted records, like trigger, or OUTPUT DELETED.* -- or use something to compare against, like a snapshot, a backup, a history table.

A completely different approach, which does require a refactoring of your example, would be to not delete from the table, but to have a separate table of deleted item ids (or to have a field in the table showing the row s status). So you could then just select on those data instead. (This would wrap around @Damir s observation that you cannot differentiate between deletions and insert errors.)

This is a good answer by @Tristan Bailey.

MySQL get missing IDs from table

also to get rid of the last added record one can use

SELECT id+1 AS id FROM users WHERE id NOT IN (SELECT id-1 FROM users) 
AND id != (
   SELECT `AUTO_INCREMENT` FROM  INFORMATION_SCHEMA.TABLES
   WHERE TABLE_SCHEMA =  my_db 
   AND   TABLE_NAME   =  users 
) ORDER BY 1;




相关问题
How to write this T-SQL WHERE condition?

I ve got two tables: TableA Col1 Col2 TableB Col3 Col4 I want to join them together: SELECT * from TableA join TableB ON (...) Now, in place of ... I need to write an expression ...

Customer and Order Sql Statement

TSQL query to select all records from Customer that has an Order and also select all records from customer that does not have an Order. The table Customer contains a primary key of CustomerID. The ...

Recommended way of querying multiple Versioned tables

Have a win 2003 box with MSSQL 2005 running on it. There is a database which is populated every morning with new/modified SalesOrder made the previous day. The database has several tables: SalesOrder, ...

update duplicate record

I have a table with the following fields Id Name IsPublic i need to write a sql query that updates IsPublic to false where name has a duplicate. Only one of the duplicates should have IsPublic = ...

Define variable to use with IN operator (T-SQL)

I have a Transact-SQL query that uses the IN operator. Something like this: select * from myTable where myColumn in (1,2,3,4) Is there a way to define a variable to hold the entire list "(1,2,3,4)"? ...

Selecting records during recursive stored procedure

I ve got a content management system that contains a hierarchical structure of categories, with sub-categories subject to different ordering options at each level. Currently, that s retrieved by a (...

热门标签