복붙노트

[SQL] 어떻게 SQL로 카운터를 실행에 "차이"를 찾을 수 있습니까?

SQL

어떻게 SQL로 카운터를 실행에 "차이"를 찾을 수 있습니까?

나는 SQL 테이블에 카운터 열에서 최초의 "차이"를 찾아 싶습니다. 값 1,2,4 및 5가있는 경우 예를 들어, 나는 3을 찾아 싶습니다.

나는 물론 순서대로 값을 얻을 수동으로 통과,하지만 난 SQL에서 그것을 할 수있는 방법이있을 것입니다 있는지 알고 싶습니다 수 있습니다.

또한, 다른 DBMS의 작업, 매우 표준 SQL해야한다.

해결법

  1. ==============================

    1.에서 MySQL과 PostgreSQL을 :

    에서 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 서버의 경우 :

    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
    

    오라클의 경우 :

    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
    
  2. ==============================

    2.귀하의 답변 당신이 첫 번째 값 아이디 = 1이있는 경우 모든 작업의 ​​벌금, 그렇지 않으면이 차이는 감지되지 않습니다. 테이블 ID 값이 3,4,5을 경우 예를 들어, 쿼리는 6을 반환합니다.

    귀하의 답변 당신이 첫 번째 값 아이디 = 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) 
    
  3. ==============================

    3.이이 작업을 수행하는 매우 표준 SQL 방법은 정말 아니지만, 절을 제한하는 어떤 형태의 당신이 할 수있는

    이이 작업을 수행하는 매우 표준 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
    

    (신탁)

  4. ==============================

    4.내 머리에 와서 가장 먼저하는 일. 확실하지가 전혀이 길을 갈 수있는 좋은 아이디어지만 작동해야합니다. 테이블 t이고 컬럼 C 가정하자 :

    내 머리에 와서 가장 먼저하는 일. 확실하지가 전혀이 길을 갈 수있는 좋은 아이디어지만 작동해야합니다. 테이블 t이고 컬럼 C 가정하자 :

    편집 :이 하나가 빠르게 틱 될 수있다 (짧은!)

  5. ==============================

    5.다른 시스템에서 테스트 할 수 있지만 표준 보인다 ... -이 SQL 서버에서 작동

    다른 시스템에서 테스트 할 수 있지만 표준 보인다 ... -이 SQL 서버에서 작동

    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을 반환합니다.

  6. ==============================

    6.다음 솔루션 :

    다음 솔루션 :

    순차적으로 다음 절 "와"및 예약 번호 순서화 행은 내부 간극 이상으로 ID를 찾고, 행 번호에 참여하지만, 그렇게 한 후에 행과 이전 행을 비교할으로 1만큼 오프셋 회 결과를 재사용 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
    
  7. ==============================

    7.내부는 모든 가능한 값이 뷰 또는 순서에 가입 할 수 있습니다.

    내부는 모든 가능한 값이 뷰 또는 순서에 가입 할 수 있습니다.

    어떤 테이블하지? 테이블을 확인합니다. 난 항상 그냥이 주변에 더미 테이블을 유지한다.

    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) ;
    
  8. ==============================

    8.PostgreSQL을 위해

    PostgreSQL을 위해

    재귀 쿼리를 사용합니다 예.

    특정 범위에서 틈을 발견 할 경우에 유용 할 수 있습니다 (표가 빈 상태 (empty)의 경우는 반면 다른 예는하지 않습니다, 심지어 작동합니다)

    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
    
  9. ==============================

    9.내 추측:

    내 추측:

    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;
    
  10. ==============================

    10.모든 것을 지금까지 언급이 하나를 차지한다. 그것은 더 값뿐만 아니라 존재하지 않는 경우로 설정됩니다 시작 지점으로 공을 포함한다. 또한 다치 키의 다른 부분에 대한 적절한 위치를 첨가. 이것은 단지 SQL 서버에서 테스트되었습니다.

    모든 것을 지금까지 언급이 하나를 차지한다. 그것은 더 값뿐만 아니라 존재하지 않는 경우로 설정됩니다 시작 지점으로 공을 포함한다. 또한 다치 키의 다른 부분에 대한 적절한 위치를 첨가. 이것은 단지 SQL 서버에서 테스트되었습니다.

    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
    
  11. ==============================

    11.나는 그것을하는 빠른 방법을 썼다. 확실하지이 가장 효율적이지만 일을 가져옵니다. 그것은 당신에게 차이를 이야기하지만, 이전과의 격차 후 당신에게 ID를 알려줍니다하지 않는 주 (간격이 여러 값이 될 수 명심 그래서 예를 1,2,4,7,11 등을위한)

    나는 그것을하는 빠른 방법을 썼다. 확실하지이 가장 효율적이지만 일을 가져옵니다. 그것은 당신에게 차이를 이야기하지만, 이전과의 격차 후 당신에게 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

  12. ==============================

    12.

    select min([ColumnName]) from [TableName]
    where [ColumnName]-1 not in (select [ColumnName] from [TableName])
    and [ColumnName] <> (select min([ColumnName]) from [TableName])
    
  13. ==============================

    13.여기에 기준 A의 SQL 솔루션입니다 변화없이 모든 데이터베이스 서버에서 실행 :

    여기에 기준 A의 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);
    

    에 대한 행동에 참조;

  14. ==============================

    14.그것은 빈 테이블 또는 네거티브 값으로도 작동합니다. 그냥 SQL 서버 2012에서 테스트

    그것은 빈 테이블 또는 네거티브 값으로도 작동합니다. 그냥 SQL 서버 2012에서 테스트

     select min(n) from (
    select  case when lead(i,1,0) over(order by i)>i+1 then i+1 else null end n from MyTable) w
    
  15. ==============================

    15.당신은 파이어 버드 3를 사용하는 경우이 가장 우아하고 간단하다 :

    당신은 파이어 버드 3를 사용하는 경우이 가장 우아하고 간단하다 :

    select RowID
      from (
        select `ID_Column`, Row_Number() over(order by `ID_Column`) as RowID
          from `Your_Table`
            order by `ID_Column`)
        where `ID_Column` <> RowID
        rows 1
    
  16. ==============================

    16.

                -- 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
    
  17. ==============================

    17.찾을 방법의 대부분은 MySQL은 매우, 매우 느리게 실행합니다. 다음은 MySQL의 <8.0에 대한 내 솔루션입니다. 끝까지 초 말 ~ 근처의 격차 1M 기록에서 테스트. 확실하지가 다른 SQL 맛을 맞는 경우.

    찾을 방법의 대부분은 MySQL은 매우, 매우 느리게 실행합니다. 다음은 MySQL의 <8.0에 대한 내 솔루션입니다. 끝까지 초 말 ~ 근처의 격차 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
    
  18. ==============================

    18.당신의 카운터가 1 일부터 시작되며이 때 빈 시퀀스의 첫 번째 숫자 (1)를 생성하려면, 여기에 오라클 유효 첫 번째 대답에서 코드의 수정 된 부분은 다음과 같습니다

    당신의 카운터가 1 일부터 시작되며이 때 빈 시퀀스의 첫 번째 숫자 (1)를 생성하려면, 여기에 오라클 유효 첫 번째 대답에서 코드의 수정 된 부분은 다음과 같습니다

    SELECT
      NVL(MIN(id + 1),1) AS gap
    FROM
      mytable mo  
    WHERE 1=1
      AND NOT EXISTS
          (
           SELECT  NULL
           FROM    mytable mi 
           WHERE   mi.id = mo.id + 1
          )
      AND EXISTS
         (
           SELECT  NULL
           FROM    mytable mi 
           WHERE   mi.id = 1
         )  
    
  19. ==============================

    19.

    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]
    
  20. ==============================

    20.열의 번호 (1부터 시작) 양의 정수가있는 경우 여기에 쉽게 해결하는 방법입니다. (ID를 가정하면 열 이름입니다)

    열의 번호 (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
    
  21. from https://stackoverflow.com/questions/1312101/how-do-i-find-a-gap-in-running-counter-with-sql by cc-by-sa and MIT license