2012-04-17 37 views
6

khi tôi DELETE, làm ví dụ, id 3, tôi có điều này:cách tìm "lỗ hổng" trong cột auto_increment?

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

bây giờ, tôi muốn tìm kiếm id thiếu (s), bởi vì tôi muốn để điền id lần nữa với:

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

có cách nào để tìm kiếm "lỗ hổng" trong chỉ mục auto_increment không?

cảm ơn!

+7

Tại sao bạn muốn thực hiện việc này? Những "lỗ hổng" như vậy là _normal_ trong hoạt động cơ sở dữ liệu hàng ngày và không phải là mối quan tâm. Nếu điều này là do một số khái niệm sai lầm về tính thẩm mỹ, hãy chống lại nó. – Oded

+6

Bạn không nên. Một auto_increment chỉ nên làm công việc của mình, và điều đó có nghĩa là lỗ có thể được thực hiện. Nếu bạn bắt đầu rối tung với điều đó, bạn sẽ gặp rắc rối sau này. Chỉ cần để cho họ được. – Nanne

+0

Chưa kể rằng nếu ID bị xóa vẫn được tham chiếu ở đâu đó, tức là thông qua bảng liên kết được đánh dấu/không được cập nhật, thì việc thêm hàng mới vào bằng ID đó sẽ tạo ra các sự cố không mong muốn. Theo Oded, Nanne, chỉ cần rời khỏi AI để thực hiện công việc của mình. –

Trả lời

13

Bạn có thể tìm thấy những giá trị hàng đầu của những khoảng trống như thế này:

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, câu trả lời hay. – davidethell

+1

nếu bạn có gab lớn hơn 1 thì sao? nếu bạn có 14 và 20, nó sẽ chỉ hiển thị 19 – Diego

+0

Xin lỗi, tôi có nghĩa là khoảng cách * – Diego

0

Trước tiên, tôi đồng ý với những ý kiến ​​mà bạn không nên cố gắng điền vào lỗ. Bạn sẽ không thể tìm thấy tất cả các lỗ với một câu lệnh SQL đơn. Bạn sẽ phải lặp qua tất cả các số có thể bắt đầu bằng 1 cho đến khi bạn tìm thấy một lỗ. Bạn có thể viết một hàm sql để làm điều này cho bạn mà sau đó có thể được sử dụng trong một hàm. Vì vậy, nếu bạn đã viết một hàm gọi là find_first_hole sau đó bạn có thể gọi nó trong một chèn như:

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

Tôi nghĩ rằng cách duy nhất bạn có thể làm điều này là với một vòng lặp: Bất kỳ giải pháp khác wont làm chương trình khoảng trống lớn hơn 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 

kết quả:

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

mục đích của AUTO_INCREMENT là để tạo ra định danh duy nhất và vô nghĩa đơn giản cho các hàng của bạn. Ngay sau khi bạn định sử dụng lại các ID đó, chúng không còn độc đáo nữa (không phải ít nhất là theo thời gian) để tôi có ấn tượng rằng bạn không sử dụng đúng công cụ cho công việc. Nếu bạn quyết định loại bỏ AUTO_INCREMENT, bạn có thể thực hiện tất cả các lần chèn bằng cùng một thuật toán.

Như về mã SQL, truy vấn này sẽ phù hợp với hàng hiện có với các hàng có ID tiếp theo:

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

Ví dụ:

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

Vì vậy, thật dễ dàng để lọc ra các hàng và nhận được khoảng cách đầu tiên:

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 

Hãy coi đây là điểm khởi đầu vì nó vẫn cần chỉnh sửa:

  • Bạn cần xem xét trường hợp số thấp nhất có sẵn là số thấp nhất có thể.
  • Bạn cần khóa bàn để xử lý các lần chèn đồng thời.
  • Trong máy tính của tôi, nó chậm như địa ngục với các bảng lớn.
+0

cảm ơn bạn đã bổ sung thêm thông tin (Trong máy tính của tôi nó chậm như địa ngục với các bảng lớn.) – skyline26

0

Đây là khoảng trống & vấn đề về đảo, xem câu trả lời của tôi (và các câu trả lời khác) herehere. Trong hầu hết các trường hợp, khoảng cách & các vấn đề về đảo được giải quyết một cách trang nhã nhất bằng cách sử dụng CTE đệ quy, không có sẵn trong mysql.

Các vấn đề liên quan