テーブルの正規化とINSERT方法について

このQ&Aのポイント
  • プログラム素人の初心者が、カラムをいちいち作るテーブルのメンテナンスについて悩んでいます。テーブルを正規化し、INSERT文を効率的に実行する方法を知りたいです。
  • MYSQLでは、同じPRIMARY KEYを持つレコードをINSERTすることはできません。そのため、重複するPRIMARY KEYを回避する方法を教えてください。
  • PerlでIDごとにまとめてレコードを取得し、配列に格納する方法を知りたいです。具体的には、IDが1のレコードを全て取得する方法を教えてください。
回答を見る
  • ベストアンサー

簡単に正規化したい

プログラム素人です。 初心者なのでこんなテーブルを思いつくのですが、これってカラムをいちいち作らないといけないので後のメンテが大変な気がします CREATE TABLE hoge( id INT PRIMARY KEY, item1 VARCHAR(255), value1 INT, item2 VARCHAR(255), value2 INT, item3 VARCHAR(255), value3 INT ); こんな感じのテーブルにどんどんINSERTしていきたいのです CREATE TABLE hoge( id INT PRIMARY KEY, item VARCHAR(255), value INT ); 聞きたいこと MYSQL側 IDにPRIMARY KEYが付いているのですが2つ同じPRIMARY KEYはINSERTでききませんよね?どうすればいいでしょうか? perl側 IDごとにまとめて取得して配列に入れる方法はありますか? idが1のアイテムを全部取得して配列に入れる方法がわかりません(他にいい方法があったらお願いします) よろしくお願いします

  • flash0
  • お礼率97% (297/306)
  • MySQL
  • 回答数3
  • ありがとう数3

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

  • ベストアンサー
回答No.2

なんかidの使い方に強い違和感がありますが、 > IDにPRIMARY KEYが付いているのですが2つ同じPRIMARY KEYはINSERTでききませんよね?どうすればいいでしょうか? primary keyにしなければよいのでは? CREATE TABLE hoge( id INT, item VARCHAR(255), value INT ); > IDごとにまとめて取得して配列に入れる方法はありますか? whereつきでselect文を発行すれば特定のidのものだけを取得出来ます。 select * from hoge where id = '1'; 例えば、こんな感じ? my $id = 1; my $rows = $dbh->selectall_arrayref('select * from hoge where id = ?', {Columns=>{id=>undef, item=>undef, value=>undef}}, $id); prepare、executeのスタイルを取りたいならこういう書き方もありですが。 sub GetRows { my ($dbh, $id) = @_; my $sth = $dbh->prepare('select * from hoge where id = ?'); $sth->execute($id); my @rows = (); while (my $row = $sth->fetchrow_hashref()) { push(@rows, $row); } $sth->finish; return \@rows; } 余談ですが、idというのは普通identityやidentificationの略で、固有の番号を示すのに使われると思うので、それで2つ以上のものが取得できるというのはちょっと違和感があります。idというよりむしろgroup_idなのでは。 groupで共通する内容はgroupのテーブルを作ってそこに入れ、group_idはgroupのテーブルのidを指す外部キーにしそうなものですが。

flash0
質問者

お礼

お答え頂きありがとうございます >whereつきでselect文を発行すれば特定のidのものだけを取得出来ます。 whereで指定した場合id全部取得できるんですね。1つしかできないと勘違いしていました >prepare、executeのスタイルを取りたいならこういう書き方もありですが。 すっごい勉強になりました。 >groupのテーブルを作ってそこに入れ、group_idはgroupのテーブルのidを指す外部キーにする idでやったことをgroup_idでやればいいのでしょうか?この場合idの意味ってありますか?ちなみにidは登録者番号です CREATE TABLE group( id INT PRIMARY KEY, group_id INT, item VARCHAR(255), value INT );

その他の回答 (2)

回答No.3

> whereで指定した場合id全部取得できるんですね。1つしかできないと勘違いしていました PerlのDBIについての説明にざっと目を通しておくと良いかもしれません。 http://dbi.perl.org/ http://search.cpan.org/~timb/DBI/DBI.pm また、"Perl DBI"で検索すると様々な方の解説記事を見つけられます。公式ドキュメントを読んでもピンと来ない場合は検索してみましょう。 > idでやったことをgroup_idでやればいいのでしょうか?この場合idの意味ってありますか?ちなみにidは登録者番号です 基本的にそういうことです。ただ、登録者番号ならregistrant_idなどと名付けるのでは。 行ごとに固有の番号が振ってあると、その行のデータを指定して取り扱うときになにかと便利だと思います。普通に考えて、データの複数ページにわたる表示、削除や変更をする場合、idがあったほうが楽ではありませんか。 例えば、Webのフォームなどで登録者IDごとにデータの一覧表示をして、削除するものをそこから選ぶ場合、IDさえフォームから送ってもらえると削除するものが一意に決まり、簡単に削除出来ますよね。また、IDで整列して表示すれば複数ページにわたっる表示が必要な場合に簡単に重複なく次のページを表示できます。

flash0
質問者

お礼

丁寧な回答ありがとうございました いろいろ勉強になりました 勉強不足なのを痛感しましたのでmysqlの本を買うことのしました。

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

上のhogeテーブルと下のhogeテーブルの相関関係がわかりません 同じものなのか、別の処理をしたいのか もう少し具体的な例を書いて、結果としてどういう集計を想定しているかによって テーブルの設計はかわってくると思います ちなみにプログラム初心者とのことですがperlが前提なのでしょうか?

flash0
質問者

お礼

テーブルはこれから作るところです 相関関係はなにもありません、例として表示しました 登録IDごとに、登録したアイテムを効率的にまとめて取得したいだけです 今回はperlです

関連するQ&A

  • AUTO_INCREMENTのあるテーブルにinsertできません(長文)

    mysql5.0.27(RedhatLinux 9)です。 属性のひとつがAUTO_INCREMENTになっているテーブルhogeに、データをinsertしたいのですが、「コラムの数が合致しない」というエラーで、insertできません。 Webをいろいろ漁って、AUTO_INCREMENTの属性は明示的に指定しないようだと理解しました。冗長で申し訳ないのですが、エラーが出た状態のものを、そのまま掲載させていただきます(テーブル名や属性名のみ変更しました)。 状態をまとめると、以下のようになります。 ・下記のテーブル定義で、テーブルは普通にcreateできた。 ・descで確認しても、ちゃんとテーブルはできているよう。 ・下記のinsert文で、その下のエラーメッセージが出て、データを登録できない。 ・どうみても、コラム数は合っている(と思う)。 ・下記のテーブル定義の属性数を適当に減らす(id, item1, item4, item6くらいにする)と、エラーが出ずデータがちゃんとinsertできる。 私はなにか、とんてもない勘違いをしているのでしょうか?かなりの時間試行錯誤しているのですが、一向にわかりません。。。 ===== テーブル定義 ===== CREATE TABLE hoge ( id MEDIUMINT UNSIGNED AUTO_INCREMENT NOT NULL, item1 VARCHAR (64) NOT NULL, item2 VARCHAR (64) NOT NULL, item3 VARCHAR (32) NOT NULL, item4 VARCHAR (64), item5 VARCHAR (64), item6 VARCHAR (16) NOT NULL, CONSTRAINT PK_HOGE PRIMARY KEY (id) ) type=innodb; CREATE INDEX IDX_HOGE_1 ON hoge(item1); CREATE INDEX IDX_HOGE_2 ON hoge(item2); CREATE INDEX IDX_HOGE_3 ON hoge(item3); CREATE INDEX IDX_HOGE_4 ON hoge(item4); CREATE INDEX IDX_HOGE_5 ON hoge(item6); ===== descの出力 ===== +---------------------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------------+-----------------------+------+-----+---------+----------------+ | id | mediumint(8) unsigned | NO | PRI | NULL | auto_increment | | item1 | varchar(64) | NO | MUL | | | | item2 | varchar(64) | NO | MUL | | | | item3 | varchar(32) | NO | MUL | | | | item4 | varchar(64) | YES | MUL | NULL | | | item5 | varchar(64) | YES | | NULL | | | item6 | varchar(16) | NO | MUL | | | +---------------------+-----------------------+------+-----+---------+----------------+ 7 rows in set (0.00 sec) ===== insert文 ===== insert into hoge (item1, item2, item3, item4, item5, item6) values ( 'data1','data2', 'data3', 'data4', 'data5', 'data6'); ===== エラーメッセージ ===== ERROR 1136 (21S01) at line 1: Column count doesn't match value count at row 1 長文大変申し訳ありません。よろしくお願いします。

  • MySQL SELECTの指定について

    まず、御覧頂きありがとうございます。 早速質問なのですが、 CREATE TABLE `hoge` ( `id` int(8) NOT NULL, `name` varchar(30) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `hoge` (`id`, `name`) VALUES (1, 'hogeA'), (2, 'hogeB'), (3, 'hogeC'), (4, 'hogeD'); CREATE TABLE `test` ( `id` int(8) NOT NULL, `name` varchar(30) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `test` (`id`, `name`) VALUES (1, 'testA'), (4, 'testD'); という値が入ってるテーブルがあるとします。(長くなってすみません) で、 hoge.id と test.id が重複した場合 test.name を表示させたいです。 期待値としては id,name 1.testA 2,hogeB 3,hogeC 4,testD になります。 業務でJoinを使うようなテーブル構造にそもそもしないというのもあり、クリティカルなSQLコードに不慣れで御知恵を借りたく質問させて頂きました。 よろしくお願いします。

    • ベストアンサー
    • MySQL
  • MySQLのFOREIGN KEYについて

     MySQLのFOREIGN KEYについて質問です。 下記のようにitemテーブルを作ってからarrivalhistoryテーブルを作ろうとすると ERROR 1005 (HY000): Can't create table 'xxx_db.arrivalhistory' (errno: 150) というエラーが出てしまいます。 自分でもForeign keyの作り方等調べてはみたのですが、 上手く解決することができません。 どなたかアドバイス下さい。お願いします。 ・親 create table item ( id bigint not null primary key, itemno VARCHAR(50) ) engine=InnoDB; ・子 create table arrivalhistory( id int primary key, itemno varchar(50), arrivaldate date, index(itemno), foreign key(itemno) references item(itemno) on update cascade on delete cascade ) engine=InnoDB;

    • ベストアンサー
    • MySQL
  • 空きのID番号を取得する方法

    いつもお世話になっております。 create table AAA( ID int(6) primary key not null auto_increment, DATA varchar(30), )engine=MyISAM; というテーブルにおいて、 insertをすると、IDが1から順に割り振られていきますが、 途中のレコードをdeleteすると、そこが空きのID番号となってしまい、 次にinsertすると、空き番号が残ってしまいます。 やりたいことは、その空き番号を有効活用するために、 auto_incrementを使用せずに、空き番号を適当に取得して、 insertをしたいのです。 何か効率的な良い方法をご存知の方がいらっしゃいましたら、 ご教授いただけると幸いです。 よろしくお願いいたします。

    • ベストアンサー
    • MySQL
  • テーブル自体のバックアップ

    教えてください。 今オラクルのDBにTEST1テーブルが存在するとします。 ------TEST1--------------------- id varchar(5) Primary Key name varchar(20) old int -------------------------------- 今このテーブルとまったく同じデータを持ち、同じ構成のテーブルTEST2を 作成したいと考えています。 (1)create table TEST2( id varchar(5) primary key, name varchar(20), old int ); (2)insert into TEST2( id, name, old) values (select id, name, old from TEST1); としてTEST2テーブルを作成して、TEST1のデータを格納していますが、 他の方法はないでしょうか? たとえばこんなコマンドはありませんが、 COPY TEST1 TEST2 とか、 オラクルマネージャみたいなもので、 コピペして、名前をTEST2にする とかなんでもいいです。 TEST1のバックアップをとりたいのですが・・・・ すみません、わかりづらい説明で。 宜しくお願い致しますm(_ _)m

  • 最初に挿入された行だけ取得したい

    このジャンルでお願いします。 次のようなテーブルで CREATE TABLE IF NOT EXISTS user ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(32) NOT NULL, PRIMARY KEY(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO user (name) VALUES ('user1'); INSERT INTO user (name) VALUES ('user2'); INSERT INTO user (name) VALUES ('user3'); CREATE TABLE IF NOT EXISTS item ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(32) NOT NULL, PRIMARY KEY(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO item (name) VALUES ('item1'); INSERT INTO item (name) VALUES ('item2'); INSERT INTO item (name) VALUES ('item3'); CREATE TABLE IF NOT EXISTS user_item ( id int(11) NOT NULL AUTO_INCREMENT, user_id INT, item_id INT, PRIMARY KEY(id), FOREIGN KEY (item_id) REFERENCES user(id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (user_id) REFERENCES item(id) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO user_item (user_id, item_id) VALUES (1, 1); INSERT INTO user_item (user_id, item_id) VALUES (2, 1); INSERT INTO user_item (user_id, item_id) VALUES (3, 2); INSERT INTO user_item (user_id, item_id) VALUES (1, 2); INSERT INTO user_item (user_id, item_id) VALUES (1, 3); INSERT INTO user_item (user_id, item_id) VALUES (3, 3); user_itemテーブルでのselectで、 user_idが1で一番最初に挿入された行だけ を取得したいのですが、どのようなSQL文にすれば良いのでしょうか? この例なら INSERT INTO user_item (user_id, item_id) VALUES (1, 1);←取得 INSERT INTO user_item (user_id, item_id) VALUES (2, 1); INSERT INTO user_item (user_id, item_id) VALUES (3, 2); INSERT INTO user_item (user_id, item_id) VALUES (1, 2);←user_id=3が最初に挿入されているので取得しない INSERT INTO user_item (user_id, item_id) VALUES (1, 3);←取得 INSERT INTO user_item (user_id, item_id) VALUES (3, 3);

    • ベストアンサー
    • MySQL
  • insert後のプライマリキーの取得

    タイトルの通りなのですが テーブルがこんな感じでtest_stringをインサートしてその後に test_idを受け取りたいのですが何か方法はないでしょうか。 CREATE TABLE test ( test_id int(8) AUTO_INCREMENT , test_string VARCHAR(100), PRIMARY KEY (test_id) ); こんな風にしても1ばかり返ってきます。 String sql = "SELECT * FROM test;" int primarykey = st.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);

  • トランザクションとlast_insert_id

    トランザクション中にinsertする予定のテーブル(未コミット)のauto_increment値を取得することはできるのでしょうか。 以下のような処理を期待しているのですが、hoge1テーブルのauto_increment値が取得できずに困っております。last_insert_id に関わらず、hoge1テーブルのauto_increment値が取得できる方法があれば教えてください。 (1) トランザクション開始 (2) $sql=" INSERT INTO hoge1(name) value('あああ'); "; (3) ( ロールバック ) (4) $key=mysql_insert_id(); (5) $sql2=" INSERT INTO hoge2(hoge1_primary,age) value($key,'20歳'); "; (6) ( ロールバック ) (7) コミット (8) トランザクション終了 よろしくお願いします。 環境: php5,mysql5 (InnoDB)

    • ベストアンサー
    • MySQL
  • テーブルの自動キー再割り当て

    以下sqlでテーブルhogeを作成し、idを自動キーにしています。 CREATE TABLE `hoge` ( `id` INT NOT NULL AUTO_INCREMENT, ........(省略).......... PRIMARY KEY (id) ) ENGINE=MyISAM DEFAULT CHARSET=sjis; このテーブルのレコード番号4を削除するとテーブルのidは 1,2,3,5(最終)になり, 新しいデータを追加(INSERT)するとidは 1,2,3,5,6(最終)とid番号4が欠番になります。 テーブルのidを1,2,3,4,5と続き番号に再割り当てして、新しいレコードがid番号6の挿入されるようにするにはどのようにすればよいでしょうか? sql文をご教示い頂きたくよろしくお願いします。

  • 階層構造のテーブルの行の取得について

    このジャンルでお願いします。 次のようなテーブルで CREATE TABLE IF NOT EXISTS user ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(32) NOT NULL, PRIMARY KEY(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO user (name) VALUES ('user1'); INSERT INTO user (name) VALUES ('user2'); INSERT INTO user (name) VALUES ('user3'); CREATE TABLE IF NOT EXISTS item ( id int(11) NOT NULL AUTO_INCREMENT, parent_id INT, name varchar(32) NOT NULL, FOREIGN KEY (parent_id) REFERENCES item(id) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO item (parent_id, name) VALUES (null, 'item1'); INSERT INTO item (parent_id, name) VALUES (1, 'item2'); INSERT INTO item (parent_id, name) VALUES (2, 'item3'); INSERT INTO item (parent_id, name) VALUES (3, 'item4'); INSERT INTO item (parent_id, name) VALUES (2, 'item5'); INSERT INTO item (parent_id, name) VALUES (null, 'item6'); INSERT INTO item (parent_id, name) VALUES (6, 'item7'); INSERT INTO item (parent_id, name) VALUES (null, 'item8'); CREATE TABLE IF NOT EXISTS user_item ( id int(11) NOT NULL AUTO_INCREMENT, user_id INT, item_id INT, type varchar(16) NOT NULL, PRIMARY KEY(id), FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (item_id) REFERENCES item(id) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO user_item (user_id, item_id, type) VALUES (1, 1, 'allow'); INSERT INTO user_item (user_id, item_id, type) VALUES (1, 3, 'deny'); INSERT INTO user_item (user_id, item_id, type) VALUES (1, 7, 'allow'); user_itemのuser_idが1のitemの行を取得したいのですが、 その条件として ・user_itemテーブルのtypeが'allow'のitem_id以下のitemの行 ・ただしtypeが'deny'のitem_id以下の行は除く この例だと、user_itemの INSERT INTO user_item (user_id, item_id, type) VALUES (1, 1, 'allow'); の行によってitemテーブルの INSERT INTO item (parent_id, name) VALUES (null, 'item1'); INSERT INTO item (parent_id, name) VALUES (1, 'item2'); INSERT INTO item (parent_id, name) VALUES (2, 'item3'); INSERT INTO item (parent_id, name) VALUES (3, 'item4'); INSERT INTO item (parent_id, name) VALUES (2, 'item5'); が取得候補になりますが、 INSERT INTO user_item (user_id, item_id, type) VALUES (1, 3, 'deny'); によって INSERT INTO item (parent_id, name) VALUES (2, 'item3'); INSERT INTO item (parent_id, name) VALUES (3, 'item4'); の行は除かれ、 INSERT INTO item (parent_id, name) VALUES (null, 'item1'); INSERT INTO item (parent_id, name) VALUES (1, 'item2'); INSERT INTO item (parent_id, name) VALUES (2, 'item5'); の行が取得されます。 つまりitemテーブルにおいて上の階層の直近の(user_itemと結合して取得した)typeが 'allow'である場合のみ取得したいのです。 INSERT INTO item (parent_id, name) VALUES (null, 'item1');←取得 INSERT INTO item (parent_id, name) VALUES (1, 'item2');←取得 INSERT INTO item (parent_id, name) VALUES (2, 'item3'); INSERT INTO item (parent_id, name) VALUES (3, 'item4'); INSERT INTO item (parent_id, name) VALUES (2, 'item5');←取得 INSERT INTO item (parent_id, name) VALUES (null, 'item6'); INSERT INTO item (parent_id, name) VALUES (6, 'item7');←取得 INSERT INTO item (parent_id, name) VALUES (null, 'item8'); 複雑ではありますが、これはどのようなSQL文にすれば良いのでしょうか?

    • ベストアンサー
    • MySQL