SQL 테이블의 카운터 열에서 첫 번째 “간격”을 찾고 싶습니다. 예를 들어 1, 2, 4, 5 값이 있다면 3을 찾고 싶습니다.
물론 값을 순서대로 가져 와서 수동으로 살펴볼 수 있지만 SQL에서 수행하는 방법이 있는지 알고 싶습니다.
또한 다양한 DBMS에서 작동하는 표준 SQL이어야합니다.
답변
에서 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
답변
첫 번째 값 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
(신탁)
답변
내 머릿속에 처음으로 떠오른 것. 이런 식으로가는 것이 좋은 생각인지 확실하지 않지만 작동해야합니다. 테이블이 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
답변
이것은 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을 반환합니다.
답변
다음 솔루션 :
- 테스트 데이터를 제공합니다.
- 다른 갭을 생성하는 내부 쿼리; 과
- SQL Server 2012에서 작동합니다.
” with “절 에서 순서가 지정된 행에 순차적으로 번호 를 매긴 다음 행 번호의 내부 조인을 사용하여 결과를 두 번 재사용하지만 이전 행과 이후 행을 비교하기 위해 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) ;