• ベストアンサー

ある条件の最大値+1を初番するにはロックが必要ですか?

以下のテーブルでcolumn毎に連番を振る場合、 テーブルロックが必要でしょうか? テーブル test id column 1 a 2 a 1 b 新規データ登録手順 1.トランザクション 2.select max(id)+1 from test where column = b for update 3.insert test into (id,column) values (selectで取得した値,b) 4.トランザクション終了 これで、column毎に登録されているIDの最大値+1で 重複せずにデータのINSERTが保障されるでしょうか?

  • php4
  • お礼率42% (373/888)
  • MySQL
  • 回答数4
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
  • nora1962
  • ベストアンサー率60% (431/717)
回答No.3

一応動くと思いますが ・ロックの粒度が大きい。'b'についてMAX(ID)を取得して挿入する処理の間  他のカラムの取得もロックされる。  同時実行性に問題はないか。  後、ロック時間が長くなるとMysqlのinnodb_lock_wait_timeoutによって  処理がエラーになる場合がある。 点が気になります。 独自に( column, max_id )を持つ発番テーブルを持った方がいいのではな いかと思います。columnが主キーです。

php4
質問者

お礼

そうなんです。ロック行が多すぎるので心配しておりました。 なるほど。確かにおっしゃる通り、InnoDBの場合、 発番テーブルを持つ方が良さそうです。ありがとうございました。

その他の回答 (3)

回答No.4

テーブルは、InnoDBである必要がありますか? MyISAMでもよいなら、複合(複数列)インデクスにして、2番目の構成列をauto_incrementにすることで、実装が容易になります。 create table `test` (`id` int auto_increment, `column` varchar(5), primary key(`column`,`id`)) 上記のような定義にすることで、`column`列の値毎に`id`列に通番が自動採番されます。 http://dev.mysql.com/doc/refman/4.1/ja/example-auto-increment.html

php4
質問者

お礼

す、すごいっす。目がうろこです。 そんな裏技ができたとは・・ InnoDBである必要はないので、MyISAMでやってみますね。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.2

テーブルtestではidがダブっている時点で本来のidとしての機能を果たしていませんね column管理用に別テーブルをつくり、idをプライマリにしてauto incrementを つけて管理するのがよろしいのでは?

php4
質問者

補足

すみません、説明が不足しておりませした。 プライマリーキーは、id,columnになります。 column a のIncrement値は2 column b のIncrement値は1 つまり次ぎに、aのユーザーが登録したら、3番を初番 bのユーザーが登録したら、2番を初番したいのです。 ちなみに、columnのパターンは無限にありテーブルをわけるわけにも いきません。

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.1

IDにUNIQUE属性を付けていればいいのではないですか? この例では1が二つあるからエラーになりますが。

関連するQ&A

  • トランザクションとテーブルロック

    初心者の質問で申し訳ありません。 トランザクションで複数のテーブルを更新する時、テーブルロックはかかっているのでしょうか。 具体的に言うと、 BEGIN TRAN a  INSERT INTO A VALUES('data1')  INSERT INTO B VALUES('data1','data2')  INSERT INTO C VALUES('data1','data2','data3') COMMIT TRAN a とするとき、テーブルA,B,Cはあらかじめロックしておく必要があるのでしょうか。 アドバイスお願いいたします。

  • バルクINSERT直後に、最後のIncremet値は取得できますか?

    PHPからMySQLへトランザクションを使わずに、 INSERT INTO test (id,count) VALUES (5,5),(6,6) のようにINSERTした直後に、SELECT LAST_INSERT_ID(); としても、5が返却されてしまいます。 これはMySQLの仕様でしょうか? 又、 SELECT LAST_INSERT_ID() ではなく、 SELECT LAST_INSERT_ID() FROM test; のようにテーブル名を指定する方法は何か意味があるのでしょうか? テーブル名を指定すると、テーブルにあるレコード数分 データが返却されてしまいました。。

    • ベストアンサー
    • MySQL
  • 入力値と外部キーをINSERTするには

    追加したいカラムが3つあるとしまして、そのうち2つはフォームからの入力値で、残り1つは別テーブルのIDをWHEREで引っ張ってきてINSERTしたい場合、INSERT...VALUES()とINSERT...SELECT構文を組み合わせないとダメかと思うのですが、組み合わせるとうまくいきません。2つの文に分けるしかないのでしょうか? やりたいことは下の感じのSQLです。が、解釈してくれません。 INSERT INTO room(A, B, C) VALUES (1, 2, SELECT other_table.id FROM other_table WHERE other_table.id = 1");

    • ベストアンサー
    • MySQL
  • SQLでできますか?

    SQLでできますか? INSERT INTO test (A) VALUES (B)というSQLを発行したいのですが、このSQLのVALUESのBにあたる部分を正規表現的に指定して、一度のクエリで以下のような結果を得たいのです。 1.テーブルhogeのpiyoカラムの値の先頭がappleになっている行を探す。 2.(1.)で抽出した行のidの値をBとする。 例えば、以下のようにです。 ■皆様が回答してくださるSQL文(1クエリで行いたい) ???????????? ■皆様が回答してくださるSQL文と同等の意味を持つSQL群 INSERT INTO test (A) VALUES (100) INSERT INTO test (A) VALUES (101) INSERT INTO test (A) VALUES (102) ■テーブルhoge _____id_____piyo__________created 1. 100 applebanana 2009/01/02 2. 101 apple_12345 2009/01/03 3. 102 appleXXXXXX 2009/01/04 4. 103 bananananan 2009/01/05 5. 104 ringogogogo 2009/01/06 分かりにくい説明ですが、お詳しい方、どうかご回答の程を宜しくお願いいたします。

    • ベストアンサー
    • MySQL
  • max+1で初番する場合 for updateは必要ですか?

    AutoIncrementでなく、 あるコードの中の最大値+1で番号を初番する場合、 1.トランザクション開始 2.select max(no) from master where aru_code = 1 for update 3.insert into master values (2で取得したnoとaru_code=1) 4.トランザクション終了 というように、for updateで行ロックをかけないと 同じ番号が初番されてしまう可能性があるでしょうか?

    • ベストアンサー
    • MySQL
  • INSERT時にデータ登録とmaxの発番がしたい

    <環境> SQLSERVER 2012 入力フォームに、入力した後で、DBに登録した際に、 依頼Noに、既にあるデータのMAX+100の値を登録したいです。 依頼NoにMAX+100の連番をふることは以下の方法でできたのですが、 INSERT INTO テーブル1(依頼No) SELECT MAX(依頼No)+100 AS NEW_ID FROM テーブル1 入力フォームのデータと登録と同時に、依頼Noを振りたいのですができません。 以下のように書いてみましたが、 根本的に間違っていると思うので、いい方法をご教授いただけたらと思います。 ※iraibi は入力フォームで、依頼日を入力した値です。 INSERT INTO テーブル1 (依頼No,依頼日) VALUES ('SELECT MAX(依頼書No)+100 AS NEW_ID FROM テーブル1','" & iraibi & "') 宜しくお願いいたします。

  • データ登録時、重複エラーを避けたい

    MYSQLのデータベースの、IDという項目が主キーのTESTというテーブルに、データをに登録する際、 既に主キーが同じデータがない場合に、という条件をつけたいのですが、 下のように書くと、エラーになってしまいます。 INSERT INTO TEST (ID, NAME) VALUES ('a', 'abc') WHERE NOT EXISTS (SELECT * FROM TEST WHERE ID = 'a'); どうしたらよいか教えてください。

    • ベストアンサー
    • MySQL
  • Insert Into Select での重複について

    DB:SQLServer2000 こんにちは お世話になっております。 トランザクションのテーブルA から ワークのテーブルBへInsert Into Select を使用してデータを格納しているのですが、その際に重複が発生してしまいます。 テーブルA 主キーあり テーブルB 主キーなし Delete B Insert into B select 項目1,項目2,・・・ from A With(Nolock) where 日付項目 = 20080101 テーブルAの主キー項目は全てテーブルBへInsertしており、Insert完了後のテーブルBの中身を見ると、まれに全く同じデータが2件出来ていることがあります。 このInsert into selectが実行されている間に、テーブルAに対して登録更新が行われることもあります。 色々と試してはいるのですが、原因が特定できずに困っております。 もし何かお気づきになられる方がいらっしゃいましたら、ご教示下さい。 よろしくお願い致します。

  • フィールドをデフォルト0にする

    フィールドをデフォルト0にする方法が知りたいです。 以下のようなサンプルがります。 drop table test_a; create table test_a ( name varchar2(10), a number(1), b number(1), c number(1) ) insert into test_a (name) values ('AAA'); insert into test_a (name,a) values ('BBB', NULL); insert into test_a (name,a,b) values ('CCC', NULL,NULL); select * from test_a; この状態では、a,b,cはNULLですが、a,b,cの値をデフォルト値で0にしたい為、 update test_a set a = 0, b = 0, c = 0; として、データを直して、次回から insert into test_a (name) values ('DDD'); とすると、nameがDDDの時もa,b,cが0となるようにテーブル定義を変えたいのですが 既存のテーブルをそのままで、途中から変更する方法が知りたいです。

  • トランザクションについて

    トランザクションについての質問なのですが、下にある1のSQLを実行すると 'a'だけ登録されるのは、分かるのですが、 2のSQLを実行すると、'c'と'd'の両方が登録されてしまいます。 私的には、両方登録されないのかなぁと思っていたのですが・・・ COMMITが来た時点で、START TRANSACTIONの開始位置は、 あまり関係ないということなのでしょうか? よろしくお願いします。 1. START TRANSACTION; insert into test values('a'); START TRANSACTION; insert into mtuser values('b'); ROLLBACK; COMMIT; 2. START TRANSACTION; insert into test values('c'); START TRANSACTION; insert into mtuser values('d'); COMMIT; ROLLBACK; 環境:Mysql4.1.19

    • ベストアンサー
    • MySQL