回答:
でMySQLとPostgreSQL:
SELECT  id + 1
FROM    mytable mo
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    mytable mi 
        WHERE   mi.id = mo.id + 1
        )
ORDER BY
        id
LIMIT 1
でSQL Server:
SELECT  TOP 1
        id + 1
FROM    mytable mo
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    mytable mi 
        WHERE   mi.id = mo.id + 1
        )
ORDER BY
        id
でOracle:
SELECT  *
FROM    (
        SELECT  id + 1 AS gap
        FROM    mytable mo
        WHERE   NOT EXISTS
                (
                SELECT  NULL
                FROM    mytable mi 
                WHERE   mi.id = mo.id + 1
                )
        ORDER BY
                id
        )
WHERE   rownum = 1
ANSI (どこでも機能し、最も効率が悪い):
SELECT  MIN(id) + 1
FROM    mytable mo
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    mytable mi 
        WHERE   mi.id = mo.id + 1
        )
スライディングウィンドウ機能をサポートするシステム:
SELECT  -- TOP 1
        -- Uncomment above for SQL Server 2012+
        previd
FROM    (
        SELECT  id,
                LAG(id) OVER (ORDER BY id) previd
        FROM    mytable
        ) q
WHERE   previd <> id - 1
ORDER BY
        id
-- LIMIT 1
-- Uncomment above for PostgreSQL
              URL。
                    [1, 2, 11, 12]、これだけが見つかります3。私が見つけて欲しいのは、代わりに3-10です。基本的に、すべてのギャップの始まりと終わりです。SQL(私の場合はMySql)を活用する独自のpythonスクリプトを作成する必要があるかもしれないことは理解していますが、SQLで希望どおりに近づけることができれば幸いです(ギャップがある200万行のテーブルがある場合、だから私はそれをより小さな断片にスライスし、それにいくつかのSQLを実行する必要があります)。1つのクエリを実行してギャップの始まりを見つけ、次に別のクエリを実行してギャップの終わりを見つけ、2つのシーケンスを「マージソート」できると思います。
                    NULL、ではなくを取得し0ます。これは、すべてのデータベースに当てはまります。
                    最初の値がid = 1の場合、すべての回答は正常に機能します。それ以外の場合、このギャップは検出されません。たとえば、テーブルID値が3、4、5の場合、クエリは6を返します。
私はこのようなことをしました
SELECT MIN(ID+1) FROM (
    SELECT 0 AS ID UNION ALL 
    SELECT  
        MIN(ID + 1)
    FROM    
        TableX) AS T1
WHERE
    ID+1 NOT IN (SELECT ID FROM TableX) 
              これを行うための非常に標準的なSQLの方法は実際にはありませんが、何らかの形の制限句を使用すると、
SELECT `table`.`num` + 1
FROM `table`
LEFT JOIN `table` AS `alt`
ON `alt`.`num` = `table`.`num` + 1
WHERE `alt`.`num` IS NULL
LIMIT 1
(MySQL、PostgreSQL)
または
SELECT TOP 1 `num` + 1
FROM `table`
LEFT JOIN `table` AS `alt`
ON `alt`.`num` = `table`.`num` + 1
WHERE `alt`.`num` IS NULL
(SQLサーバー)
または
SELECT `num` + 1
FROM `table`
LEFT JOIN `table` AS `alt`
ON `alt`.`num` = `table`.`num` + 1
WHERE `alt`.`num` IS NULL
AND ROWNUM = 1
(Oracle)
最初に頭に浮かんだこと。この方法を採用するのが良いかどうかはわかりませんが、うまくいくはずです。テーブルがtあり、列がc:
SELECT t1.c+1 AS gap FROM t as t1 LEFT OUTER JOIN t as t2 ON (t1.c+1=t2.c) WHERE t2.c IS NULL ORDER BY gap ASC LIMIT 1
編集:これはダニより速く(そして短く!)なるかもしれません:
SELECT min(t1.c)+1 AS gap FROM t as t1 LEFT OUTER JOIN t as t2 ON (t1.c+1=t2.c) WHERE t2.c IS NULL
LEFT OUTER JOING t2が必要ですt2。
                    これはSQL Serverで機能します-他のシステムではテストできませんが、標準的なようです...
SELECT MIN(t1.ID)+1 FROM mytable t1 WHERE NOT EXISTS (SELECT ID FROM mytable WHERE ID = (t1.ID + 1))
where句に開始点を追加することもできます...
SELECT MIN(t1.ID)+1 FROM mytable t1 WHERE NOT EXISTS (SELECT ID FROM mytable WHERE ID = (t1.ID + 1)) AND ID > 2000
したがって、2003、2004が存在しない2000、2001、2002、2005の場合、2003が返されます。
次のソリューション:
順序付けされた行に " with "句で順番に番号を付け、その結果を行番号の内部結合で2回再利用しますが、前の行と後の行を比較するために1だけオフセットして、より大きなギャップを持つIDを探します1.要求された以上のものですが、より広く適用できます。
create table #ID ( id integer );
insert into #ID values (1),(2),    (4),(5),(6),(7),(8),    (12),(13),(14),(15);
with Source as (
    select
         row_number()over ( order by A.id ) as seq
        ,A.id                               as id
    from #ID as A WITH(NOLOCK)
)
Select top 1 gap_start from (
    Select 
         (J.id+1) as gap_start
        ,(K.id-1) as gap_end
    from       Source as J
    inner join Source as K
    on (J.seq+1) = K.seq
    where (J.id - (K.id-1)) <> 0
) as G
内部クエリは以下を生成します:
gap_start   gap_end
3           3
9           11
外側のクエリは以下を生成します:
gap_start
3
              可能なすべての値を持つビューまたはシーケンスへの内部結合。
テーブルなし?テーブルを作る。私はいつもこのためにダミーのテーブルを用意しています。
create table artificial_range( 
  id int not null primary key auto_increment, 
  name varchar( 20 ) null ) ;
-- or whatever your database requires for an auto increment column
insert into artificial_range( name ) values ( null )
-- create one row.
insert into artificial_range( name ) select name from artificial_range;
-- you now have two rows
insert into artificial_range( name ) select name from artificial_range;
-- you now have four rows
insert into artificial_range( name ) select name from artificial_range;
-- you now have eight rows
--etc.
insert into artificial_range( name ) select name from artificial_range;
-- you now have 1024 rows, with ids 1-1024
そして、
 select a.id from artificial_range a
 where not exists ( select * from your_table b
 where b.counter = a.id) ;
              ために PostgreSQL
再帰クエリを使用する例。
これは、特定の範囲のギャップを見つけたい場合に役立ちます(テーブルが空の場合でも機能しますが、他の例では機能しません)。
WITH    
    RECURSIVE a(id) AS (VALUES (1) UNION ALL SELECT id + 1 FROM a WHERE id < 100), -- range 1..100  
    b AS (SELECT id FROM my_table) -- your table ID list    
SELECT a.id -- find numbers from the range that do not exist in main table
FROM a
LEFT JOIN b ON b.id = a.id
WHERE b.id IS NULL
-- LIMIT 1 -- uncomment if only the first value is needed
              私の推測:
SELECT MIN(p1.field) + 1 as gap
FROM table1 AS p1  
INNER JOIN table1 as p3 ON (p1.field = p3.field + 2)
LEFT OUTER JOIN table1 AS p2 ON (p1.field = p2.field + 1)
WHERE p2.field is null;
              これはこれまで述べたすべてを説明します。開始点として0が含まれます。値が存在しない場合もデフォルトになります。また、複数値キーの他の部分に適切な場所を追加しました。これはSQL Serverでのみテストされています。
select
    MIN(ID)
from (
    select
        0 ID
    union all
    select
        [YourIdColumn]+1
    from
        [YourTable]
    where
        --Filter the rest of your key--
    ) foo
left join
    [YourTable]
    on [YourIdColumn]=ID
    and --Filter the rest of your key--
where
    [YourIdColumn] is null
              簡単な方法を書いた。これが最も効率的かどうかはわかりませんが、作業は完了です。これはギャップを通知するのではなく、ギャップの前後のIDを通知することに注意してください(ギャップは複数の値になる可能性があることに注意してください。たとえば、1、2、4、7、11など)
例としてsqliteを使用しています
これがあなたのテーブル構造なら
create table sequential(id int not null, name varchar(10) null);
そして、これらはあなたの行です
id|name
1|one
2|two
4|four
5|five
9|nine
クエリは
select a.* from sequential a left join sequential b on a.id = b.id + 1 where b.id is null and a.id <> (select min(id) from sequential)
union
select a.* from sequential a left join sequential b on a.id = b.id - 1 where b.id is null and a.id <> (select max(id) from sequential);
https://gist.github.com/wkimeria/7787ffe84d1c54216f1b320996b17b7e
以下は、変更なしですべてのデータベースサーバーで実行される標準のSQLソリューションです。
select min(counter + 1) FIRST_GAP
    from my_table a
    where not exists (select 'x' from my_table b where b.counter = a.counter + 1)
        and a.counter <> (select max(c.counter) from my_table c);
実際に見てください。
            -- PUT THE TABLE NAME AND COLUMN NAME BELOW
            -- IN MY EXAMPLE, THE TABLE NAME IS = SHOW_GAPS AND COLUMN NAME IS = ID
            -- PUT THESE TWO VALUES AND EXECUTE THE QUERY
            DECLARE @TABLE_NAME VARCHAR(100) = 'SHOW_GAPS'
            DECLARE @COLUMN_NAME VARCHAR(100) = 'ID'
            DECLARE @SQL VARCHAR(MAX)
            SET @SQL = 
            'SELECT  TOP 1
                    '+@COLUMN_NAME+' + 1
            FROM    '+@TABLE_NAME+' mo
            WHERE   NOT EXISTS
                    (
                    SELECT  NULL
                    FROM    '+@TABLE_NAME+' mi 
                    WHERE   mi.'+@COLUMN_NAME+' = mo.'+@COLUMN_NAME+' + 1
                    )
            ORDER BY
                    '+@COLUMN_NAME
            -- SELECT @SQL
            DECLARE @MISSING_ID TABLE (ID INT)
            INSERT INTO @MISSING_ID
            EXEC (@SQL)
            --select * from @MISSING_ID
            declare @var_for_cursor int
            DECLARE @LOW INT
            DECLARE @HIGH INT
            DECLARE @FINAL_RANGE TABLE (LOWER_MISSING_RANGE INT, HIGHER_MISSING_RANGE INT)
            DECLARE IdentityGapCursor CURSOR FOR   
            select * from @MISSING_ID
            ORDER BY 1;  
            open IdentityGapCursor
            fetch next from IdentityGapCursor
            into @var_for_cursor
            WHILE @@FETCH_STATUS = 0  
            BEGIN
            SET @SQL = '
            DECLARE @LOW INT
            SELECT @LOW = MAX('+@COLUMN_NAME+') + 1 FROM '+@TABLE_NAME
                    +' WHERE '+@COLUMN_NAME+' < ' + cast( @var_for_cursor as VARCHAR(MAX))
            SET @SQL = @sql + '
            DECLARE @HIGH INT
            SELECT @HIGH = MIN('+@COLUMN_NAME+') - 1 FROM '+@TABLE_NAME
                    +' WHERE '+@COLUMN_NAME+' > ' + cast( @var_for_cursor as VARCHAR(MAX))
            SET @SQL = @sql + 'SELECT @LOW,@HIGH'
            INSERT INTO @FINAL_RANGE
             EXEC( @SQL)
            fetch next from IdentityGapCursor
            into @var_for_cursor
            END
            CLOSE IdentityGapCursor;  
            DEALLOCATE IdentityGapCursor;  
            SELECT ROW_NUMBER() OVER(ORDER BY LOWER_MISSING_RANGE) AS 'Gap Number',* FROM @FINAL_RANGE
              ほとんどのアプローチは非常に遅く実行されmysqlます。ここに私の解決策がありmysql < 8.0ます。終了までのギャップが約1秒である1Mレコードでテストしました。他のSQLフレーバーに適合するかどうかはわかりません。
SELECT cardNumber - 1
FROM
    (SELECT @row_number := 0) as t,
    (
        SELECT (@row_number:=@row_number+1), cardNumber, cardNumber-@row_number AS diff
        FROM cards
        ORDER BY cardNumber
    ) as x
WHERE diff >= 1
LIMIT 0,1
 シーケンスは「1」から始まると想定しています。
              DECLARE @Table AS TABLE(
[Value] int
)
INSERT INTO @Table ([Value])
VALUES
 (1),(2),(4),(5),(6),(10),(20),(21),(22),(50),(51),(52),(53),(54),(55)
 --Gaps
 --Start    End     Size
 --3        3       1
 --7        9       3
 --11       19      9
 --23       49      27
SELECT [startTable].[Value]+1 [Start]
     ,[EndTable].[Value]-1 [End]
     ,([EndTable].[Value]-1) - ([startTable].[Value]) Size 
 FROM 
    (
SELECT [Value]
    ,ROW_NUMBER() OVER(PARTITION BY 1 ORDER BY [Value]) Record
FROM @Table
)AS startTable
JOIN 
(
SELECT [Value]
,ROW_NUMBER() OVER(PARTITION BY 1 ORDER BY [Value]) Record
FROM @Table
)AS EndTable
ON [EndTable].Record = [startTable].Record+1
WHERE [startTable].[Value]+1 <>[EndTable].[Value]
              列の数値が正の整数(1から始まる)の場合、簡単に解決する方法を次に示します。(IDが列名であると想定)
    SELECT TEMP.ID 
    FROM (SELECT ROW_NUMBER() OVER () AS NUM FROM 'TABLE-NAME') AS TEMP 
    WHERE ID NOT IN (SELECT ID FROM 'TABLE-NAME')
    ORDER BY 1 ASC LIMIT 1
              
LAG(id, 1, null)関数withOVER (ORDER BY id)句を使用できます。