AUTO_INCREMENTがオンになっている主キーフィールドを持つMySQLテーブルがあります。ここで他の投稿を読んだ後、私は同じ問題とさまざまな答えを持っている人々に気づきました。この機能を使用しないことを推奨する人もいれば、「修正」できないと述べる人もいます。
私は持っています:
table: course
fields: courseID, courseName
例:テーブル内のレコード数:18.レコード16、17、および18を削除すると、次のレコードのcourseIDは16になると予想されますが、最後に入力されたcourseIDは18であるため、19になります。
私のSQLの知識は驚くほどではありませんが、クエリ(またはphpMyAdminインターフェイスの設定)でこのカウントを更新または更新する方法はありますか?
このテーブルは、データベース内の他のテーブルに関連付けられます。
すべてのアドバイスを与えられて、私はこの「問題」を無視することに決めました。自動インクリメントにジョブを実行させながら、レコードを削除および追加するだけです。番号が一意の識別子としてのみ使用されており、(上記のように)businessの意味を持たないため、番号が何であるかは実際には関係ないと思います。
私の元の投稿と混同しているかもしれない人のために:私はこのフィールドを使用して、私が持っているレコードの数を知りたくありません。データベースがきれいに見えて、少し一貫性があるようにしたかっただけです。
しようとしていることは、AUTO_INCREMENT
の使用目的ではないため、危険に思えます。
最も低い未使用のキー値を見つけたい場合は、AUTO_INCREMENT
を使用せずに、キーを手動で管理してください。ただし、これは推奨される方法ではありません。
一歩下がって、「なぜキー値をリサイクルする必要があるのか?」と尋ねる署名なしINT
(またはBIGINT
)ではなく十分な大きさのキースペースを提供しますか?
アプリケーションの存続期間中に 18,446,744,073,709,551,615
以上の一意のレコードが本当にあるでしょうか?
ALTER TABLE foo AUTO_INCREMENT=1
最新のエントリを削除した場合は、次に低いエントリを使用するように設定する必要があります。同様に、19が存在しない限り、16〜18を削除すると、16を使用するように自動インクリメントがリセットされます。
EDIT:phpmyadminについて少し見逃していました。そこにも設定できます。テーブル画面に移動し、操作タブをクリックします。手動で必要なものに設定できる AUTOINCREMENT
フィールドがあります。
データベースのプライマリ自動インクリメントキーは、特定の行を一意に識別するために使用され、businessの意味は与えられません。そのため、主キーはそのままにして、たとえばcourseOrder
という別の列を追加します。次に、データベースからレコードを削除するときに、現在削除しているものよりも大きいcourseOrder
を持つすべての行のcourseOrder
列をデクリメントするために、追加のUPDATEステートメントを送信できます。
副次的な注意として、外部データベースとしてそれを参照する他のテーブルが存在する可能性があり、それを変更すると参照制約に違反する可能性があるため、リレーショナルデータベースの主キーの値を変更しないでください。
試してください:
SET @num:= 0;
UPDATE your_table SET id = @num:=(@ num + 1);
ALTER TABLE
tableName
AUTO_INCREMENT = 1;
これにより、自動インクリメントされた値がリセットされ、新しい値が作成される間、すべての行がカウントされます。
例:前
そのため、テーブルには配列が表示されます:1,2,4,5
例:AFTER(このコマンドを使用すると取得できます)
削除された値の痕跡はなく、増分された残りの部分はこの新しいカウントで続行されます。
しかし
AUTO_INCREMENT idに依存して、テーブルにあるレコードの数を知る必要はありません。 SELECT COUNT(*) FROM course
を使用する必要があります。 IDはコースを一意に識別するために存在し、他のテーブルの参照として使用できるため、IDを繰り返したり、自動インクリメントフィールドをリセットしたりしないでください。
次のようにIDを選択できます。
_set @rank = 0;
select id, @rank:=@rank+1 from tbl order by id
_
結果は、idのリストと、シーケンス内のそれらの位置です。
次のようにIDをリセットすることもできます。
_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;
_
また、次のように最初の未使用のIDを出力することもできます。
_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;
_
挿入するたびに、auto_incrementをリセットできます。
_alter table tbl auto_increment = 16
_
または、挿入時にid値を明示的に設定します。
_insert into tbl values (16, 'something');
_
通常、これは必要ありません。count(*)
と、結果セットにランキング番号を作成する機能があります。一般的なランキングは次のとおりです。
_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
_
消費額でランク付けされた顧客。
タイトルの質問への回答を探してここに来ました"MySQL - Auto Increment after delete"
しかし、私は質問でその答えを見つけることができました
次のようなものを使用して:
DELETE FROM table;
ALTER TABLE table AUTO_INCREMENT = 1;
ダリン・ディミトロフの答え 本当によく説明しているAUTO_INCREMENT
およびその使用法。後悔するかもしれないことをする前に、そこを見てください。
PS:質問自体はもっと"Why you need to recycle key values?"
および ドルフの答え それをカバーします。
私は非常にシンプルだがトリッキーな方法を得た。
行を削除するときに、IDを別の一時テーブルに保存できます。その後、メインテーブルに新しいデータを挿入すると、一時テーブルからIDを検索および選択できます。ここでチェックを使用してください。一時テーブルにIDがない場合、メインテーブルの最大IDを計算し、新しいIDを次のように設定します:new_ID = old_max_ID+1
。
注意:ここでは自動インクリメント機能を使用できません。
特に移行または開発プロセス中に、これを行う必要のある多くのシナリオを考えることができます。たとえば、2つの既存のテーブルを(複雑なセットアッププロセスの一部として)クロス結合して新しいテーブルを作成する必要があり、イベント後に主キーを追加する必要がありました。既存の主キー列をドロップしてから、これを行うことができます。
ALTER TABLE my_table ADD `ID` INT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`ID`);
稼働中のシステムの場合、特に外部キーがそれを指している他のテーブルがある場合、それは良い考えではありません。
実際にそれを修正する方法があります。最初にauto_incremented主キー列を削除してから、次のように再度追加します。
ALTER TABLE table_name DROP column_name;
ALTER TABLE table_name ADD column_name int not null auto_increment primary key first;
Mysqlクライアントソフトウェア/スクリプトを使用して、必要なレコードを削除した後、プライマリキーを開始する場所を指定できます。
削除後にトリガーを作成することを検討して、自動インクリメントの値と、表示したくないように見えるすべての行のID値を更新することができます。
したがって、同じテーブルで作業でき、自動インクリメントは、トリガーが修正する行を削除するたびに自動的に修正されます。
お勧めできません。複数のテーブルを持つ大規模なデータベースがある場合、おそらくテーブル2にidとしてユーザーIDを保存している可能性があります。
ここにあなたの問題を修正する関数があります
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();
}
}
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");
あなたがやろうとしていることは非常に危険です。これについて慎重に考えてください。自動インクリメントのデフォルトの動作には非常に正当な理由があります。
このことを考慮:
レコードは、別のテーブルと関係がある1つのテーブルで削除されます。 2番目のテーブルの対応するレコードは、監査のために削除できません。このレコードは、最初のテーブルから孤立します。新しいレコードが最初のテーブルに挿入され、シーケンシャルプライマリキーが使用される場合、このレコードは孤立にリンクされます。明らかに、これは悪いことです。自動インクリメントされたPKを使用することにより、以前に使用されたことのないIDが常に保証されます。これは、孤児が孤児のままであることを意味し、正しいことです。