質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

Q&A

解決済

3回答

8115閲覧

MySQLでオートインクリメントの値が意図した通りにならない件の解決法について

zico_teratail

総合スコア907

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

0グッド

2クリップ

投稿2016/12/25 08:20

編集2016/12/25 08:46

現在MySQL 5.5.45、InnoDBで使っています。
様々な場面で、AUTO_INCREMENTを設定した主キーの値が意図したとおりの動作にならずに困ることがあります。

特に多いのが、

  • INSERT...ON DUPLICATE KEY UPDATE
  • INSERT IGNORE
  • REPLACE

などを使った場合のインクリメントの仕方。

「SELECTしてその値が無かったらINSERT」は多くの人が望んでいる、「よくある動作」かと思われます。
一般的な人間の思考でいくと綺麗な連番になっていてほしいものですが、実際は値が飛び飛びになっていたりすることが多いですよね。

REPLACEなどは挙動をよく理解しておかないと致命的なことになりかねません。特にオートインクリメントしたidをサロゲートキーとして使っている場合は。「マニュアル読め」と言われればそれまでですが、一般的な人間の感覚からはだいぶズレた「MySQL(DB全般?)特有の動作」と言っていいのではないでしょうか。


参考:【MySQL】AUTO_INCREMENTの値が増える、飛ぶ、欠番が発生する at softelメモ

参考:insert duplicate インクリメント - Google 検索

参考:サロゲートキー - Google 検索


たとえば
id AUTO_INCREMENT 主キー
name unique
みたいなカラムがあるテーブルに「田中、鈴木、田中、山田」というデータを入れるために

SQL

1INSERT IGNORE INTO `member` (`name`) VALUES(:name);

を投げると、id値は「1,2,4」となります。
実用上はそれでも問題ないのかもしれませんが、人間の心情的にはidを連続した値にしてほしいところです。

こういうとき、地道にSELECTして値の存在を確認してからINSERT・・・などと回りくどいことをせずに一発でスマートに(連番で)解決する方法は存在するのでしょうか?
それともデータベースとはそういうものなのだ、と諦めるしかないのでしょうか?


参考:kamipo TRADITIONALでは防げないINSERT IGNOREという名の化け物 | おそらくはそれさえも平凡な日々

参考:songmuさんのツイート: "我々は何故2015年にもなってSELECTして無かったらINSERTする場合のベストパターンを確立できていないのか。"

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

それともデータベースとはそういうものなのだ、と諦めるしかないのでしょうか?

諦めましょう。
同じような質問はteratailにいくつかありますので、参考にしてください。

投稿2016/12/25 08:51

編集2016/12/25 08:57
popobot

総合スコア6586

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

zico_teratail

2016/12/26 03:39

やはりそういうものですかね。
guest

0

auto_incrementに対するそもそもの考え方が間違えていると思います
auto_incrementはレコードをconstに特定するためだけに利用すべきものです
したがって連番であるということは不要ですし、むしろ忘れてください
原則SQLにはレコード同士の間に相関関係はありません。
したがってデータが連続しているという考え方がSQL的発想ではありません。

なんらかの連番処理が必要であればSQL側でランキングを計算する手法が
幾つか用意されています。(ただし効率は悪いです)

sample

SQL

1create table tbl (id int not null unique key,val varchar(20)); 2insert into tbl values(1,'aaa'),(2,'bbb'),(4,'ccc'),(50,'ddd'),(999,'eee'); 3create view vw as select id,(select count(*)+1 from tbl as t2 where t1.id>t2.id) as renban,val from tbl as t1;

表示

SQL

1select * from vw;

投稿2016/12/26 03:25

編集2016/12/26 03:54
yambejp

総合スコア114814

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

zico_teratail

2016/12/26 03:39

データベースの理論的にはそうであるのは承知しているのですが、「人間の感情・心理的に気持ち悪いので」という理由です。 phpMyAdminなどでざっと眺めたときに欠番があるとどうも気分が悪くて・・・
yambejp

2016/12/26 03:58 編集

> 欠番があるとどうも気分が悪くて・・・ という発想が間違っていると言いたいのですがうまく伝わってないようで残念です。 どうしても連番を表示したいならviewをつくっておけばいいでしょう。 (サンプルつけました、前述の通り効率は悪いですけどね) それでも納得出来ないならデータが投入・変更・削除される度に毎回UPDATE構文でidを振り直すことです。 (SQLの運用方法としては最悪ですけどね)
zico_teratail

2016/12/26 04:08

>という発想が間違っていると言いたいのですがうまく伝わってないようで残念です。 心情的な問題なので理論的に間違っているかどうかは関係ないと言いたいのですがうまく伝わってないようで残念です。
yambejp

2016/12/26 04:12

了解、回答を削除依頼しておきました
Panzer_vor

2016/12/26 12:08

超絶な横槍ですが。 プログラムの世界は理論から成り立ってるので、 直感には反することがあるのは仕方ないと受け止めるのが吉です。 直感通りに動かないとどうしても気に入らない、 要件を満たせないのであれば、結局自作するほかありません。 個人的にはデータベースのオートインクリメントやシーケンスの仕組みは、 アクセスのあったかという事実をトリガーに動作するものという認識なので、 言うほど違和感はないかなと思ってます。 考えようによれば、 キー重複による試行失敗分が記録として分かるため、 それはそれはありかなと思いますし。
zico_teratail

2016/12/27 04:32

>Panzer_vorさん >キー重複による試行失敗分が記録として分かる なるほど、それは確かにメリットともいえますね。
Panzer_vor

2016/12/28 21:42

> zico_teratailさん 当方のDBのオートインクリメントに考え方についは上記の通りですが、 オートインクリメント絡みはDBを跨いだデータ移行なとで、ちょくちょくトラブルを生むことがあるのでご注意を。 それもあり移植性と連番の正確性を重視すると、 テーブル操作が1つ余計には増えますが、採番テーブルを用意するのが堅実かもしれませんね。 採番テーブルでの発番から、 本テーブル登録時の採番までを1つのトランザクションとしたストアドを作れば使い回しも効きますし。
guest

0

簡単なサンプルをストアドで。
考慮すべきことはまだあるし、不十分ですが。

#テーブル定義

sql

1CREATE TABLE `Sample` ( 2 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 `name` varchar(16) DEFAULT NULL, 4 PRIMARY KEY (`id`) 5) ENGINE=InnoDB DEFAULT CHARSET=utf8;

#ストアド

sql

1DELIMITER ;; 2CREATE DEFINER=`root`@`localhost` PROCEDURE `updateOrInsert`(IN id INT, IN txt VARCHAR(16)) 3BEGIN 4 5UPDATE Sample SET `name` = txt WHERE id = id; 6IF (0 = ROW_COUNT()) THEN 7 INSERT INTO Sample (id, `name`) VALUES (id, txt); 8END IF; 9 10END;; 11DELIMITER ;

#実行

sql

1CALL updateOrInsert(1, 'aaa');

投稿2016/12/25 09:22

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

zico_teratail

2016/12/26 03:39

ありがとうございます。 参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問