2012-06-19 11 views
13

Sie haben eine Tabelle, die table1id Spalte enthält, dass int(11), not null, auto_increment ist und geht von 1.SQL-Abfrage, um Datensätze gelöscht werden

Angenommen, Sie haben 10.000 Datensätze. Es ist klar, dass die ID des letzten Datensatzes 10.000 ist. Sobald Sie 3 Datensätze entfernt haben, haben Sie 9.997 Datensätze in der Tabelle, aber der letzte Datensatz-ID-Wert ist immer noch 10.000 (wenn der letzte Datensatz nicht gelöscht wurde).

Wie anzeigen, welche Datensätze mit 1 SQL-Abfrage entfernt wurden?

Vielen Dank.

+2

Erstellen Sie eine Tabelle mit 10.000 sequentiellen Werten als Nachschlagetabelle. Wählen Sie dann alle Datensätze aus Ihrer Suche aus, die in Ihrer Zieltabelle nicht vorhanden sind. * (Dies ist immer schneller als der Versuch, die fehlenden IDs dynamisch zu erzeugen.) * – MatBailie

+0

Wenn Ihr DMBS eine generate_series() - ähnliche Funktion hat (ich glaube nicht, dass mysql es hat), könnten Sie das verwenden, basierend auf {min, max }, anstelle einer fest verdrahteten kalander * tabelle *. – wildplasser

+0

+1, weil ich etwas Neues gelernt habe, indem ich antwortete :) Eine anständige Frage :) –

Antwort

5

Ich denke am einfachsten wäre eine Dummy/Temp-Tabelle mit nur IDs zu haben. 1-1000 dann linker beitreten zu diesem Tisch.

Aber sicher sein, die "gelöschten" Datensätze aus Ihrer Dummy/Temp-Tabelle zu entfernen, sobald Sie fertig sind. Ansonsten werden sie jedes Mal auftauchen.

>> EDIT < < Sie selbst beitreten tun können, wenn Sie fehlen ids sind, um herauszufinden, ....

select a.id + 1 MissingIds 
from <table> a 
left join <table> b 
    on a.id = b.id - 1 
where b.id is null 
    and a.id < 10000 
+3

Es ist einfach, aber nicht sehr professionell imo :) –

+0

alles, was Sie wirklich brauchen, ist eine Nummer Tabelle oder Möglichkeit, Zahlen im laufenden Betrieb zu generieren – dotjoe

+3

@ AndriusNaruševičius Stimme nicht zu. Manchmal ist es professionell, eine fehlgeschlagene Methode zu haben, nicht eine übertriebene. – fancyPants

1
DECLARE @myTestTable1 TABLE 
(
id INT IDENTITY(1,1) NOT NULL 
,testVal int 
) 

DECLARE @increment AS int = 1 

WHILE (@increment <= 10000) 
BEGIN 
INSERT INTO @myTestTable1 
VALUES (@increment) 

SET @increment += 1 
END 

DELETE FROM @myTestTable1 WHERE id IN (100,200,300) 

--SELECT * FROM @myTestTable1 

;WITH Missing (missnum, maxid) 
AS 
(
    SELECT 1 AS missnum, (select max(id) from @myTestTable1) 
    UNION ALL 
    SELECT missnum + 1, maxid FROM Missing 
    WHERE missnum < maxid 
    ) 
    SELECT missnum 
    FROM Missing 
    LEFT OUTER JOIN @myTestTable1 tt on tt.id = Missing.missnum 
    WHERE tt.id is NULL 
    OPTION (MAXRECURSION 0); 

Aber es braucht viel Zeit. Wir müssen die Zeit reduzieren.

2

Ich verwendete this answer als Referenz.

Sie können die folgende Abfrage verwenden, um die Lücken zu finden, die Ihnen im Wesentlichen die gelöschten Datensätze "Bereiche" geben. Im folgenden Beispiel erhalten Sie beispielsweise 2 Zeilen im Endergebnis und die Werte sind 2 und 3 sowie 6 und 7. Sie wissen also, dass Zeilen mit den IDs 2 bis 3 gelöscht wurden und Zeilen mit IDs von 6 bis 7 wurden gelöscht (für insgesamt 4 gelöschte Zeilen).

Ich glaube, das entspricht Ihrer Anforderung, das Endergebnis in "1 SQL-Abfrage" zu bekommen, und plus, keine Zwischen- oder Dummy-Tabellen werden verwendet.

delimiter $$ 
use test 
$$ 

create table mytable (id int not null auto_increment, name varchar(100), primary key (id)); 
$$ 

insert into mytable (name) values('a')$$ 
insert into mytable (name) values('b')$$ 
insert into mytable (name) values('c')$$ 
insert into mytable (name) values('d')$$ 
insert into mytable (name) values('e')$$ 
insert into mytable (name) values('f')$$ 
insert into mytable (name) values('g')$$ 
insert into mytable (name) values('h')$$ 


delete from mytable where id = 2$$ 
delete from mytable where id = 3$$ 
delete from mytable where id = 6$$ 
delete from mytable where id = 7$$ 


SELECT (t1.id + 1) as gap_starts_at 
    , (SELECT MIN(t3.id) -1 
      FROM mytable t3 
     WHERE t3.id > t1.id) as gap_ends_at 
    FROM mytable t1 
WHERE NOT EXISTS (SELECT t2.id FROM mytable t2 WHERE t2.id = t1.id + 1) 
HAVING gap_ends_at IS NOT NULL 

Ausgang:

gap_starts_at gap_ends_at 
2    3 
6    7 
1

So beginnen mit, ich der einfachste Weg, um zu zeigen, werde 10.000 Datensätze zu erzeugen. Keine riesigen Fragen, keine Variablen. Ausführungszeit: ~ 3ms. LINK

Jetzt über diesen Auslöser, dass ich versprochen habe. LINK

Wie Sie sehen können, ist es wirklich einfach, einen zu erstellen. Denken Sie daran, dass der Trigger nicht nur für verschiedene Joins nicht sinnvoll ist, sondern Sie können auch das Datum, die Benutzer-ID usw. speichern (sehr erweiterbares Beispiel). Und der Hauptpunkt von Trigger-Joins ist: es ist dir egal, wie viele Datensätze es waren/sind/werden. Sie müssen nicht über die Größe streng sein. Deshalb habe ich die Antwort sam yi nicht professionell genug genannt. Entschuldigung für das Missverständnis, ich bin mir ziemlich sicher, dass niemand von uns jemanden beleidigen wollte.

Durch das Erstellen dieses Beispiels habe ich ein paar Dinge gelernt. Hoffentlich haben Sie auch :)

+0

http://sqlfiddle.com/#!2/ab17a/1 - Ich habe eine UI-Alternative zum Befehl "delimiter" erstellt (beachten Sie die "|") unter dem Schema-Panel. Auf diese Weise können Sie Ihre Trigger-basierte Option erstellen. –

+0

Aah, ich verstehe, danke dafür. Noch eine Sache, die ich lerne: P –

+0

Wird Ihren Link verwenden, wenn Sie nichts dagegen haben :) –

Verwandte Themen