표준편차 - sql 사칙연산




SQL Server에서 사용되지 않는 최소 수 찾기 (9)

SQL Server 열에서 사용되지 않는 가장 작은 수를 어떻게 찾을 수 있습니까?

Excel에서 SQL Server 테이블로 많은 수의 수동으로 레코드 된 레코드를 가져 오려고합니다. 그들은 모두 숫자 ID (문서 번호)를 가지고 있지만 더 이상 적용되지 않는 이유 때문에 순차적으로 지정되지 않았습니다. 즉, 웹 사이트에서 새 레코드를 기록 할 때 가장 작은 가능한 문서 번호를 할당해야합니다. 0보다 큼).

일반 SQL을 통해이를 수행하는 방법이 있습니까? 아니면 TSQL / 코드에 대한 문제입니까?

감사!

편집하다

동시성 문제를 제기 한 WW 에게 특별히 감사드립니다. 이것이 웹 애플리케이션이라는 점을 감안할 때, 정의에 의해 멀티 스레드이며, 동일한 문제에 직면 한 모든 사람들은 충돌을 막기 위해 코드 또는 DB 레벨 잠금을 고려해야합니다.

LINQ

FYI - 다음 코드를 사용하여 LINQ를 통해 수행 할 수 있습니다.

var nums = new [] { 1,2,3,4,6,7,9,10};

int nextNewNum = (
    from n in nums
    where !nums.Select(nu => nu).Contains(n + 1)
    orderby n
    select n + 1
).First();

nextNewNum == 5


ID가 항상 1로 시작해야한다고 가정 해 보겠습니다.

SELECT MIN(a.id) + 1 AS firstfree
FROM (SELECT id FROM table UNION SELECT 0) a
LEFT JOIN table b ON b.id = a.id + 1
WHERE b.id IS NULL

이는 내가 생각할 수있는 모든 사례를 처리합니다. 기존 레코드를 전혀 포함하지 않습니다.

이 솔루션에 대해 싫어하는 유일한 점은 추가 조건을 두 번 포함해야한다는 것입니다.

SELECT MIN(a.id) + 1 AS firstfree
FROM (SELECT id FROM table WHERE column = 4711 UNION SELECT 0) a
LEFT JOIN table b ON b.column = 4711 AND b.id = a.id + 1
WHERE b.id IS NULL

또한 잠금 및 동시성에 대한 주석을 확인하십시오 - 간격을 채우기위한 요구 사항은 대부분 잘못된 디자인이며 문제를 일으킬 수 있습니다. 그러나 ID를 인쇄하고 인간이 타이핑 한 후 몇 시간 후에 많은 자릿수의 ID를 갖고 싶지는 않지만 낮은 자릿수는 모두 무료입니다.


Id + 1이있는 행이없는 첫 번째 행을 찾습니다.

SELECT TOP 1 t1.Id+1 
FROM table t1
WHERE NOT EXISTS(SELECT * FROM table t2 WHERE t2.Id = t1.Id + 1)
ORDER BY t1.Id

편집하다:

가장 낮은 기존 ID가 1이 아닌 특별한 경우를 처리하려면 다음과 같은 추악한 솔루션이 필요합니다.

SELECT TOP 1 * FROM (
    SELECT t1.Id+1 AS Id
    FROM table t1
    WHERE NOT EXISTS(SELECT * FROM table t2 WHERE t2.Id = t1.Id + 1 )
    UNION 
    SELECT 1 AS Id
    WHERE NOT EXISTS (SELECT * FROM table t3 WHERE t3.Id = 1)) ot
ORDER BY 1

나는 비슷한 문제에 직면했고 이것을 생각해 내었다.

Select Top 1 IdGapCheck
From (Select Id, ROW_NUMBER() Over (Order By Id Asc) AS IdGapCheck
    From dbo.table) F
Where Id > IdGapCheck
Order By Id Asc

다음은 간단한 접근법입니다. 금식 일 수는 없습니다. 처음에는 빠진 번호를 찾지 못할 것입니다.

SELECT MIN(MT1.MyInt+1)
FROM MyTable MT1
LEFT OUTER JOIN MyTable MT2 ON (MT1.MyInt+1)=MT2.MyInt
WHERE MT2.MyInt Is Null

시퀀스에 간격이 있으면 다음과 같이 첫 번째 간격을 찾을 수 있습니다.

select top 1 (found.id + 1) nextid from (select id from items union select 0) found
    where not exists (select * from items blocking
                          where blocking.id = found.id + 1)
    order by nextid asc

즉, 후계자가없는 ID를 찾아서 그 후계자를 반환하십시오. 간격이 없으면 가장 큰 기존 ID보다 하나 큰 값을 반환합니다. 자리 표시 자 ID 0을 삽입하여 ID가 ​​1로 시작하도록합니다.

이것은 적어도 n log n 시간이 소요됩니다.

Microsoft SQL에서는 insert 문에서 from 절을 사용할 수 있으므로 절차 코드에 의지 할 필요가 없습니다.


이 대답은 늦었지만 재귀 테이블 식을 사용하면 사용되지 않은 가장 작은 숫자를 찾을 수 있습니다.

CREATE TABLE Test
(
    ID int NOT NULL
)

--Insert values here

;WITH CTE AS
(
    --This is called once to get the minimum and maximum values
    SELECT nMin = 1, MAX(ID) + 1 as 'nMax' 
    FROM Test
    UNION ALL
    --This is called multiple times until the condition is met
    SELECT nMin + 1, nMax 
    FROM CTE
    WHERE nMin < nMax
)

--Retrieves all the missing values in the table. Removing TOP 1 will
--list all the unused numbers up to Max + 1
SELECT TOP 1 nMin
FROM CTE
WHERE NOT EXISTS
(
    SELECT ID
    FROM Test
    WHERE nMin = ID
)

지금까지 모든 응답에서 잠금 또는 동시성에 대한 언급이 없습니다.

다음 두 사용자가 거의 동시에 문서를 추가한다고 가정 해보십시오.

User 1                User 2
Find Id               
                      Find Id
Id = 42               
                      Id = 42
Insert (42..)  
                      Insert (42..)
                      Error!

다음 중 하나를 수행해야합니다. a) 해당 오류를 처리하고 루프를 다시 돌아가 다음 사용 가능한 ID를 찾습니다. 또는 b) 프로세스 시작시 잠금을 해제하여 1 명의 사용자 만 특정 시간에 ID를 찾습니다.


SELECT TOP 1 t1.id+1
FROM mytable t1
 LEFT OUTER JOIN mytable t2 ON (t1.id + 1 = t2.id)
WHERE t2.id IS NULL
ORDER BY t1.id;

이는 @Jeffrey Hantlin과 @Darrel Miller가 제공하는 상관 관계 부속 질의를 사용하는 응답에 대한 대안입니다.

그러나 설명하는 정책은 실제로 좋은 생각이 아닙니다. ID 값은 고유해야하지만 연속적 일 필요는 없습니다.

문서 # 42에 대한 링크가 포함 된 이메일을 보낸 다음 문서를 삭제하면 어떻게됩니까? 나중에 새 문서에 ID # 42를 다시 사용합니다. 이제 이메일 수신자가 잘못된 문서에 대한 링크를 따라갑니다!


select
    MIN(NextID) NextUsableID
from (
    select (case when c1 = c2 then 0 
            else c1 end) NextID 
    from (  select ROW_NUMBER() over (order by record_id) c1, 
                   record_id c2
            from   myTable)
)
where NextID > 0






gaps-and-islands