2012-04-17 12 views
6

gdy usunę, jako przykład, id 3, mam to:jak znaleźć "dziury" w kolumnie auto_increment?

id | name 
1 | 
2 |  
4 | 
5 | 
... 

teraz chcę, aby szukać brakującego ID (ów), ponieważ chcę, aby ponownie napełnić id z:

INSERT INTO xx (id,...) VALUES (3,...) 

Czy istnieje sposób wyszukiwania "dziur" w indeksie auto_indeksu?

dziękuję!

+7

Dlaczego chcesz to zrobić? Takie "dziury" są nienormalne w codziennej pracy z bazą danych i nie powinny stanowić problemu. Jeśli wynika to z błędnego pojęcia estetyki, przeciwstaw się temu. – Oded

+6

Nie powinieneś. Auto_increment powinien po prostu wykonywać swoją pracę, a to oznacza, że ​​można zrobić dziury. Jeśli zaczniesz się z tym bawić, napotkasz kłopoty później. Po prostu pozwól im być. – Nanne

+0

Nie wspominając, że jeśli usunięty identyfikator jest nadal przywoływany gdzieś np. Poprzez zakładkowe łącze/niezaktualizowaną tabelę, dodanie nowego wiersza z tym identyfikatorem spowoduje niezamierzone problemy. Jak oznajmił Oded, Nanne, po prostu zostaw AI do wykonania swojej pracy. –

Odpowiedz

13

można znaleźć górną wartość luki tak:

select t1.id - 1 as missing_id 
from mytable t1 
left join mytable t2 on t2.id = t1.id - 1 
where t2.id is null 
+0

+1, dobra odpowiedź. – davidethell

+1

co, jeśli masz odrobinę większą niż 1? jeśli masz 14, a potem 20, to będzie to tylko 19 – Diego

+0

Przepraszam, miałem na myśli gap * – Diego

0

Po pierwsze, zgadzam się z komentarzami, że nie należy próbować wypełniania dziur. Nie będziesz w stanie znaleźć wszystkich dziur za pomocą pojedynczej instrukcji SQL. Będziesz musiał przechodzić przez wszystkie możliwe numery zaczynając od 1, aż znajdziesz dziurę. Możesz napisać funkcję sql, aby zrobić to za Ciebie, która może być następnie użyta w funkcji. Więc jeśli napisałem funkcję o nazwie find_first_hole was mógłby następnie wywołać go we wkładce jak:

INSERT INTO xx (id, ...) VALUES (find_first_hole(), ...) 
2

Myślę, że jedynym sposobem można to zrobić za pomocą pętli: Wszelkie inne rozwiązania przyzwyczajenie pokaz luk większych niż 1:

insert into XX values (1) 
insert into XX values (2) 
insert into XX values (4) 
insert into XX values (5) 
insert into XX values (10) 

declare @min int 
declare @max int 

select @min=MIN(ID) from xx 
select @max=MAX(ID) from xx 

while @min<@max begin 
    if not exists(select 1 from XX where id = @min+1) BEGIN 
     print 'GAP: '+ cast(@min +1 as varchar(10)) 
    END 

    set @[email protected]+1 
end 

wynik:

GAP: 3 
GAP: 6 
GAP: 7 
GAP: 8 
GAP: 9 
3

Celem AUTO_INCREMENT jest tworzenie prostych i bezsensowne unikalne identyfikatory dla swoich wierszy. Jak tylko planujesz ponownie użyć tych identyfikatorów, nie są już one unikalne (przynajmniej w czasie), więc mam wrażenie, że nie używasz odpowiedniego narzędzia do pracy. Jeśli zdecydujesz się pozbyć AUTO_INCREMENT, możesz zrobić wszystkie swoje wstawki z tym samym algorytmem.

Jak o kodzie SQL, ta kwerenda będzie pasował do istniejących wierszy z wierszy, które ma następnego ID:

SELECT a.foo_id, b.foo_id 
FROM foo a 
LEFT JOIN foo b ON a.foo_id=b.foo_id-1 

np

1 NULL 
4 NULL 
10 NULL 
12 NULL 
17 NULL 
19 20 
20 NULL 
24 25 
25 26 
26 27 
27 NULL 

więc łatwo odfiltrować wiersze i uzyskać pierwsza luka:

SELECT MIN(a.foo_id)+1 AS next_id 
FROM foo a 
LEFT JOIN foo b ON a.foo_id=b.foo_id-1 
WHERE b.foo_id IS NULL 

Weź to jako punkt wyjścia, ponieważ nadal wymaga pewnych modyfikacji:

  • Należy wziąć pod uwagę przypadek, w którym najniższa dostępna liczba jest najniższą możliwą.
  • Musisz zablokować stół, aby obsługiwać współbieżne wkładki.
  • W moim komputerze jest powolny jak diabli z dużymi stołami.
+0

dzięki za dodatkowe informacje (na moim komputerze jest to powolne jak diabli z dużymi tabelami.) – skyline26

0

Jest to problem luki & wyspa, zobacz moje (i innych) odpowiada here i here. W większości przypadków problemy z wyspami są najbardziej elegancko rozwiązywane przy użyciu rekurencyjnych CTE, które nie są dostępne w mysql.

Powiązane problemy