Automatische Inkrementierung nach dem Löschen in MySQL

74

Ich habe eine MySQL-Tabelle mit einem Primärschlüsselfeld, auf dem AUTO_INCREMENT aktiviert ist. Nachdem ich andere Beiträge hier gelesen habe, habe ich Leute mit dem gleichen Problem und mit unterschiedlichen Antworten bemerkt. Einige empfehlen, diese Funktion nicht zu verwenden, andere geben an, dass sie nicht "repariert" werden kann.

Ich habe:

table: course
fields: courseID, courseName

Beispiel: Anzahl der Datensätze in der Tabelle: 18. Wenn ich die Datensätze 16, 17 und 18 lösche, würde ich erwarten, dass der nächste eingegebene Datensatz die Kurs-ID 16 hat, jedoch 19, da die zuletzt eingegebene Kurs-ID 18 war.

Meine SQL-Kenntnisse sind nicht erstaunlich, aber gibt es trotzdem eine Möglichkeit, diese Anzahl mit einer Abfrage (oder einer Einstellung in der phpMyAdmin-Oberfläche) zu aktualisieren oder zu aktualisieren?

Diese Tabelle bezieht sich auf andere in einer Datenbank.


Angesichts aller Ratschläge habe ich beschlossen, dieses „Problem“ zu ignorieren. Ich werde einfach Datensätze löschen und hinzufügen, während das automatische Inkrement seinen Job erledigt. Ich denke, es spielt keine Rolle, wie die Nummer lautet, da sie nur als eindeutige Kennung verwendet wird und keine (wie oben erwähnte) Geschäftsbedeutung hat .

Für diejenigen, die ich möglicherweise mit meinem ursprünglichen Beitrag verwechselt habe: Ich möchte dieses Feld nicht verwenden, um zu wissen, wie viele Datensätze ich habe. Ich wollte nur, dass die Datenbank ordentlich aussieht und ein bisschen konsistenter ist.

OmidTahouri
quelle
3
Was würden Sie erwarten, wenn Sie nur Datensatz 16 löschen würden?
John Boker
Guter Punkt! Ich hätte erwähnen sollen. Im Idealfall alles nach oben verschieben?
OmidTahouri
Ich stoße auf ein Problem, das in gewisser Weise das Gegenteil Ihres Problems ist. Mit anderen Worten, ich habe einen ENTITYTisch und einen ENTITY_LOGTisch. Jedes Mal, wenn ich etwas in die ENTITYTabelle einfüge, aktualisiere oder lösche , protokolliere ich diese Aktivität ENTITY_LOGzusammen mit der Aktivität der Entität in der Tabelle Id. Kürzlich hat ein Benutzer eine Reihe von Einträgen in der ENTITYTabelle gelöscht . und entsprechende Protokolleinträge wurden in der Protokolltabelle vorgenommen. Als heute ein anderer Benutzer versuchte, einen neuen Eintrag in die ENTITYTabelle aufzunehmen, war der generierte Eintrag Idderselbe wie eine zuvor gelöschte Entität! Ich benutze JdbcTemplate und InnoDB.
Web-Benutzer
@WebUser Ich verstehe nicht, warum das passieren würde. Ich bin mir ziemlich sicher (und würde es erwarten), dass MySQL sich um all das kümmert. Ich bin mir der JdbcTemplate-Seite nicht sicher - vielleicht macht es etwas dort (?). Viel Glück!
OmidTahouri
@OmidTahouri, dem stimme ich voll und ganz zu. Es ist sicherlich ein seltsames Problem. Also werde ich versuchen, das Problem zu replizieren und den Code durchzugehen. Danke für die Bestätigung!
Web-Benutzer

Antworten:

72

Was Sie versuchen, klingt gefährlich, da dies nicht die beabsichtigte Verwendung ist AUTO_INCREMENT.

Wenn Sie wirklich den niedrigsten nicht verwendeten Schlüsselwert finden möchten, verwenden Sie ihn überhaupt nicht AUTO_INCREMENTund verwalten Sie Ihre Schlüssel manuell. Dies ist jedoch KEINE empfohlene Vorgehensweise.

Machen Sie einen Schritt zurück und fragen Sie: " Warum müssen Sie Schlüsselwerte recyceln? " Stellen Sie nicht signierte INT(oder BIGINT) nicht genügend Schlüssel zur Verfügung?

Werden Sie 18,446,744,073,709,551,615im Laufe der Lebensdauer Ihrer Anwendung wirklich mehr als nur eindeutige Datensätze haben?

Dolph
quelle
1
Du hast Recht. Es ist am besten, es zu ignorieren. In Anbetracht dessen, dass dies nur für eine Aufgabe ist, werde ich nicht auf hohe Zahlen eingehen und die Lebensdauer ist sehr kurz.
OmidTahouri
4
stimmen aus einer Reihe von Gründen sehr gefährlich zu. Erstens kann es in einem Mehrbenutzersystem zu vielen, Hunderten, Tausenden von Updates pro Sekunde kommen, und der Versuch, die Auto-Inc neu zu schreiben, kann das System entweder verlangsamen oder gefährden. Zwei andere Entwickler würden nicht wissen, dass Sie dies vielleicht tun, und Datensätze über die ID verknüpfen, um das System zu beschädigen. usw.
PurplePilot
Gute Argumente. Die Antwort ließ mich zweimal überlegen. Ich jedenfalls suchte nach keinen Lücken im auto_incr. weil ich vorhatte, die IDs irgendwie zu durchlaufen. Aber ich denke, es ist besser, einfach durch die Reihen zu schleifen :)
Nils Sens
1
Also ist es einfach nicht möglich? Es gibt triftige Gründe, dies in einer Testumgebung tun zu wollen.
Michael
38
ALTER TABLE foo AUTO_INCREMENT=1

Wenn Sie die neuesten Einträge gelöscht haben, sollte dies festlegen, dass der nächstniedrigere verfügbare verwendet wird. Solange in noch keine 19 vorhanden ist, wird durch Löschen von 16-18 die automatische Inkrementierung auf 16 zurückgesetzt.


EDIT: Ich habe das bisschen über phpmyadmin verpasst. Sie können es auch dort einstellen. Gehen Sie zum Tabellenbildschirm und klicken Sie auf die Registerkarte Vorgänge. Dort gibt es ein AUTOINCREMENTFeld, das Sie manuell einstellen können.

monksp
quelle
1
Das OP KANN das, aber er sollte es nicht. Sie sollten diesen Rat wirklich überdenken, wenn man bedenkt, was das OP versucht.
Mike Sherov
10
Es ist nicht meine Aufgabe, ihm zu sagen, wie er seine Datenbank anlegen oder wie er seine Geschäftslogik umsetzt. Er erwähnte in seinem Beitrag auch, dass er andere Beiträge / Seiten gelesen hat, die besagen, dass dies eine schlechte Idee ist, sodass er weiß, dass dies keine empfohlene Vorgehensweise ist, aber trotzdem weitermacht.
Mönch
5
Dies ist die direkteste Antwort auf die einzige explizite Frage des Fragestellers. Es gibt keinen "Rat".
Air
1
Immer eine gute "Praxis", um auch zu raten, Ihre Lösung nicht zu verwenden, wenn Sie Gründe dagegen haben, die das OP möglicherweise übersehen hat.
ToBe
4
Obwohl dies ist eine schlechte Praxis ist es die beste Antwort , weil es tatsächlich beantwortet , was der OP gefragt
Jojodmo
16

Primäre Autoincrement-Schlüssel in der Datenbank werden verwendet, um eine bestimmte Zeile eindeutig zu identifizieren, und sollten keine geschäftliche Bedeutung erhalten. Lassen Sie also den Primärschlüssel unverändert und fügen Sie eine weitere Spalte hinzu, die beispielsweise aufgerufen wird courseOrder. Wenn Sie dann einen Datensatz aus der Datenbank löschen, möchten Sie möglicherweise eine zusätzliche UPDATE-Anweisung senden, um die courseOrderSpalte aller Zeilen zu dekrementieren , die courseOrdergrößer sind als die, die Sie gerade löschen.

Als Randnotiz sollten Sie niemals den Wert eines Primärschlüssels in einer relationalen Datenbank ändern, da es andere Tabellen geben kann, die ihn als Fremdschlüssel referenzieren, und wenn Sie ihn ändern, kann dies gegen referenzielle Einschränkungen verstoßen.

Darin Dimitrov
quelle
er will eine Zählung aufrechterhalten, keine Bestellung. Das UPDATE scheint unnötig.
Mike Sherov
Wenn er eine Zählung beibehalten möchte, müssen keine zusätzlichen Spalten hinzugefügt werden. Die einfache countAggregatfunktion erledigt den Job.
Darin Dimitrov
Okay danke. Viele Antworten / Kommentare in so kurzer Zeit! : O ich versuche sie alle aufzunehmen. Ich werde in die
Zählfunktion
12

Versuchen :

SET @num: = 0;

UPDATE your_table SET id = @num: = (@ num + 1);

ALTER TABLE tableNameAUTO_INCREMENT = 1;

Dadurch wird der automatisch inkrementierte Wert zurückgesetzt und anschließend jede Zeile gezählt, während ein neuer Wert dafür erstellt wird.

Beispiel: vorher

  • 1: erster Wert hier
  • 2: zweiter Wert hier
  • X: Wert gelöscht
  • 4: Der Rest der Tabelle
  • 5: Der Rest des Restes ..

In der Tabelle wird also das Array angezeigt: 1,2,4,5

Beispiel: AFTER (wenn Sie diesen Befehl verwenden, erhalten Sie)

  • 1: erster Wert hier
  • 2: zweiter Wert hier
  • 3: Der Rest der Tabelle
  • 4: der Rest des Restes

Keine Spur des gelöschten Wertes, und der Rest des inkrementierten Werts wird mit dieser neuen Zählung fortgesetzt.

ABER

  1. Wenn irgendwo in Ihrem Code etwas den automatisch inkrementierten Wert verwendet ... verursacht diese Zuordnung möglicherweise ein Problem.
  2. Wenn Sie diesen Wert nicht in Ihrem Code verwenden, sollte alles in Ordnung sein.
Claod
quelle
Wenn Sie alte Werte beibehalten und das auto_increment auf den Maximalwert setzen möchten, müssen Sie den Maximalwert ermitteln: 1. Wenn Sie sie bestellen, nehmen Sie den Wert der letzten Zeile / 2. und setzen Sie das Auto-Inkrement auf diesen Maximalwert + 1 in Ihrem Code.
Claod
Wirklich zu schätzen. Es hilft mir sehr, das Problem meines Freundes zu lösen. Ich habe diese Antwort nach langem Suchen im Internet gefunden.
Ariful Islam
4

Sie sollten sich nicht auf die AUTO_INCREMENT-ID verlassen, um zu erfahren, wie viele Datensätze Sie in der Tabelle haben. Sie sollten verwenden SELECT COUNT(*) FROM course. IDs dienen dazu, den Kurs eindeutig zu identifizieren, und können als Referenzen in anderen Tabellen verwendet werden. Sie sollten daher keine IDs wiederholen und nicht versuchen, das Feld für die automatische Inkrementierung zurückzusetzen.

Mike Sherov
quelle
Ich denke, er denkt, es ist eine Art Fehler. MySQL ist 20 Jahre alt. Dies ist definitiv kein Versehen. Es gibt einen sehr guten Grund, warum beim automatischen Inkrementieren keine Schlüssel recycelt werden. Du bist völlig richtig, Mike.
Charles Robertson
2

Sie können die IDs wie folgt auswählen:

set @rank = 0;
select id, @rank:=@rank+1 from tbl order by id

Das Ergebnis ist eine Liste der IDs und ihrer Positionen in der Sequenz.

Sie können die IDs auch folgendermaßen zurücksetzen:

set @rank = 0;
update tbl a join (select id, @rank:=@rank+1 as rank from tbl order by id) b
  on a.id = b.id set a.id = b.rank;

Sie können auch einfach die erste nicht verwendete ID wie folgt ausdrucken:

select min(id) as next_id from ((select a.id from (select 1 as id) a
  left join tbl b on a.id = b.id where b.id is null) union
  (select min(a.id) + 1 as id from tbl a left join tbl b on a.id+1 = b.id
  where b.id is null)) c;

Nach jeder Einfügung können Sie das auto_increment zurücksetzen:

alter table tbl auto_increment = 16

oder setzen Sie den ID-Wert beim Einfügen explizit:

insert into tbl values (16, 'something');

In der Regel ist dies nicht erforderlich, und Sie haben count(*)die Möglichkeit, eine Rangfolge in Ihren Ergebnismengen zu erstellen. Ein typisches Ranking könnte sein:

set @rank = 0;
select a.name, a.amount, b.rank from cust a,
  (select amount, @rank:=@rank+1 as rank from cust order by amount desc) b
  where a.amount = b.amount

Kunden nach ausgegebenem Betrag geordnet.

user262976
quelle
2

Ich bin hierher gekommen, um eine Antwort auf die Titelfrage zu suchen, "MySQL - Auto Increment after delete"aber ich konnte nur in den Fragen eine Antwort darauf finden

Mit etwas wie:

DELETE FROM table;
ALTER TABLE table AUTO_INCREMENT = 1;

Beachten Sie, dass Darin Dimitrovs Antwort sehr gut erklärt AUTO_INCREMENTund verwendet wird. Schauen Sie dort nach, bevor Sie etwas tun, das Sie vielleicht bereuen.

PS: Die Frage selbst ist mehr "Why you need to recycle key values?"und Dolphs Antwort deckt das ab.

Michel Ayres
quelle
2

Ich kann mir viele Szenarien vorstellen, in denen Sie dies möglicherweise tun müssen, insbesondere während eines Migrations- oder Entwicklungsprozesses. Zum Beispiel musste ich gerade eine neue Tabelle erstellen, indem ich zwei vorhandene Tabellen miteinander verband (als Teil eines komplexen Einrichtungsprozesses), und dann musste ich nach dem Ereignis einen Primärschlüssel hinzufügen. Sie können die vorhandene Primärschlüsselspalte löschen und dies dann tun.

ALTER TABLE my_table ADD `ID` INT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`ID`);

Für ein Live-System ist dies keine gute Idee, insbesondere wenn andere Tabellen mit Fremdschlüsseln darauf verweisen.

Peter Smartt
quelle
1

Ich habe eine sehr einfache, aber knifflige Methode.

Während Sie eine Zeile löschen, können Sie die IDs in einer anderen temporären Tabelle beibehalten. Wenn Sie danach neue Daten in die Haupttabelle einfügen, können Sie IDs suchen und aus der temporären Tabelle auswählen. Verwenden Sie hier also eine Überprüfung. Wenn die temporäre Tabelle keine IDs hat, berechnen Sie die maximale ID in der Haupttabelle und legen Sie die neue ID wie folgt fest : new_ID = old_max_ID+1.

Hinweis: Sie können die automatische Inkrementierungsfunktion hier nicht verwenden.

arefin2k
quelle
1

Was Sie versuchen zu tun, ist sehr gefährlich. Überlegen Sie genau. Es gibt einen sehr guten Grund für das Standardverhalten der automatischen Inkrementierung.

Bedenken Sie:

Ein Datensatz wird in einer Tabelle gelöscht, die eine Beziehung zu einer anderen Tabelle hat. Der entsprechende Datensatz in der zweiten Tabelle kann aus Prüfungsgründen nicht gelöscht werden. Dieser Datensatz wird ab der ersten Tabelle verwaist. Wenn ein neuer Datensatz in die erste Tabelle eingefügt wird und ein sequentieller Primärschlüssel verwendet wird, ist dieser Datensatz jetzt mit dem Orphan verknüpft. Das ist natürlich schlecht. Durch die Verwendung einer automatisch inkrementierten PK wird immer eine ID garantiert, die noch nie zuvor verwendet wurde. Dies bedeutet, dass Waisen Waisen bleiben, was richtig ist.

Charles Robertson
quelle
1

Es gibt tatsächlich eine Möglichkeit, dies zu beheben. Zuerst löschen Sie die Primärschlüsselspalte auto_incremented und fügen sie dann erneut hinzu:

ALTER TABLE table_name DROP column_name;
ALTER TABLE table_name ADD column_name int not null auto_increment primary key first;
Geni Jaho
quelle
0

Sie können Ihre MySQL-Client-Software / -Skript verwenden, um anzugeben, wo der Primärschlüssel nach dem Löschen der erforderlichen Datensätze beginnen soll.

Sarfraz
quelle
0

Möglicherweise möchten Sie nach dem Löschen einen Trigger erstellen, um den Wert der automatischen Inkrementierung und den ID-Wert aller Zeilen zu aktualisieren, die nicht den gewünschten Angaben entsprechen.

Sie können also mit derselben Tabelle arbeiten und das automatische Inkrement wird automatisch korrigiert, wenn Sie eine Zeile löschen, die der Trigger repariert.

Aloui Khalil
quelle
Link
Aloui Khalil
0

Es ist definitiv nicht zu empfehlen. Wenn Sie eine große Datenbank mit mehreren Tabellen haben, haben Sie möglicherweise eine Benutzer-ID als ID in Tabelle 2 gespeichert. Wenn Sie Tabelle 1 neu anordnen, wird die beabsichtigte Benutzer-ID wahrscheinlich nicht die beabsichtigte ID für Tabelle 2 sein.

Joshua Omwoyo
quelle
0

MYSQL Query Auto Increment Solution. Es funktioniert perfekt, wenn Sie während der Testphase der Software viele Datensätze eingefügt haben. Jetzt möchten Sie Ihre Anwendung live auf Ihrem Client starten und die automatische Inkrementierung ab 1 starten.

Um unerwünschte Probleme zu vermeiden, aus Sicherheitsgründen zuerst .sqlDatei exportieren .
Befolgen Sie dann die folgenden Schritte:

  • Schritt 1) ​​Erstellen Sie zuerst die Kopie einer vorhandenen Tabelle MySQL Command, um eine Kopie zu erstellen:

    CREATE TABLE new_Table_Name  SELECT * FROM existing_Table_Name;
    

    Die genaue Kopie einer Tabelle wird mit allen Zeilen außer Einschränkungen erstellt.
    Einschränkungen wie Auto Increment und Primary Key werden nicht kopiertnew_Table_name

  • Schritt 2) Alle Zeilen löschen Wenn in der Testphase keine Daten eingefügt wurden und dies nicht sinnvoll ist. Wenn Daten wichtig sind, fahren Sie direkt mit Schritt 3 fort.

    DELETE from new_Table_Name;
    
  • Schritt 3) Um Einschränkungen hinzuzufügen, wechseln Sie zur Struktur einer Tabelle

    • 3A) Fügen Sie die Primärschlüsseleinschränkung aus der Option Mehr hinzu (falls erforderlich).
    • 3B) Fügen Sie die Option "Automatische Inkrementierung" aus der Option "Ändern" hinzu. Für diesen Satz Definierter Wert als None.
Rupesh Ganesh Bhoir
quelle
-1
if($id == 1){ // deleting first row
            mysqli_query($db,"UPDATE employees  SET id=id-1 WHERE id>1");
        }
        else if($id>1 && $id<$num){ // deleting middle row
            mysqli_query($db,"UPDATE employees  SET id=id-1 WHERE id>$id");
        }
        else if($id == $num){ // deleting last row
            mysqli_query($db,"ALTER TABLE employees AUTO_INCREMENT = $num");
        }
        else{
            echo "ERROR";
        }

        mysqli_query($db,"ALTER TABLE employees AUTO_INCREMENT = $num");
Vaso Nadiradze
quelle
1
MySQL ist eine relationale Datenbank. Wenn mehrere Tabellen vorhanden sind, muss eine Beziehung zwischen den Tabellen definiert werden. Und das geschieht mit ID-Spalten. Das Problem bei diesem Ansatz besteht darin, dass beim Umnummerieren der Indizes einer Tabelle Auswirkungen auf alle Tabellen auftreten, zu denen eine Beziehung besteht.
Liamvictor
-1

Hier ist eine Funktion, die Ihr Problem behebt

    public static void fixID(Connection conn, String table) {

    try {
        Statement myStmt = conn.createStatement();
        ResultSet myRs;
        int i = 1, id = 1, n = 0;
        boolean b;
        String sql;

        myRs = myStmt.executeQuery("select max(id) from " + table);
        if (myRs.next()) {
            n = myRs.getInt(1);
        }
        while (i <= n) {
            b = false;
            myRs = null;
            while (!b) {
                myRs = myStmt.executeQuery("select id from " + table + " where id=" + id);
                if (!myRs.next()) {
                    id++;
                } else {
                    b = true;
                }
            }

            sql = "UPDATE " + table + " set id =" + i + " WHERE id=" + id;
            myStmt.execute(sql);
            i++;
            id++;
        }

    } catch (SQLException e) {
        e.printStackTrace();
    }
}
dani bilel
quelle