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

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

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

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

Q&A

3回答

5258閲覧

MySQLにおける多対多の集計方法について

smiley-_-smiley

総合スコア26

MySQL

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

0グッド

2クリップ

投稿2015/11/13 08:19

社内の資産管理台帳を作りたいと考えています。

管理対象は、社員が利用しているPCと、各PCにインストールしているソフトです。

以下の3点が前提条件としてあります。
1.一人の社員が複数のPCを使用する場合がある
2.ソフトはライセンスの種別により利用可能対象が異なる
・タイプA:PC1台につき1ライセンス
・タイプB:ユーザー1人につき2台まで
3.各ソフトウェアごと利用状況(使用中/在庫)を集計したい

多対多の関係になるため、連結用のテーブルを使うことを考えましたが、
どのようなSQLを書けば3の集計ができるのかわかりませんでした。

そもそも設計として正しいのか、SQLはどのようになるのかをご教示いただければと思います。

[ユーザー]


[連結用]────[パソコン]


[ソフトウェア]


[ユーザー]
ID 社員
1 田中 一郎
2 山田 太郎
3 太田 光博
4 佐川 和夫
5 太田 明日香
6 篠原 沙希
7 朝霞 寛子

[パソコン]
ID PC識別番号
1 H001
2 H002
3 H003
4 H004
5 H005
6 H006

[ソフトウェア]
ID ソフト名称 タイプ 購入数
1 Office2010 Professional A 5
2 Office2010 Personal B 5
3 Office2013 Professional B 5
4 Office365 B 20
5 Illustrator CS4 A 4
6 Photoshop CS4 A 4
7 Dreamweaver CS4 A 4
8 InDesign CS4 B 3
9 Illustrator CS5 B 6
10 Photoshop CS5 B 6
11 Dreamweaver CS5 B 6
12 InDesign CS5 B 2
13 CreativeCloud B 2
14 Acrobat A 30

[連結用]
社員 PC ソフト
田中 一郎 H001 Office2010 Professional
田中 一郎 H001 Acrobat
山田 太郎 H003 Acrobat
山田 太郎 H003 CreativeCloud
佐川 和夫 H004 Acrobat
佐川 和夫 H004 Illustrator CS5
佐川 和夫 H004 Photoshop CS5
佐川 和夫 H004 Dreamweaver CS5
篠原 沙希 H002 Office2013 Professional
篠原 沙希 H002 Acrobat
田中 一郎 H006 Office2013 Professional
田中 一郎 H006 Acrobat
朝霞 寛子 H003 Illustrator CS4
朝霞 寛子 H003 Photoshop CS4
朝霞 寛子 H003 Dreamweaver CS4

※実際には各IDが入ります

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

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

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

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

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

guest

回答3

0

多対多の関連を表すのに関連テーブルを使うのは定石ではありますが、関連テーブルの設計に少し問題があるように思います。

以下の仕様が実際の業務にマッチするかはわかりませんが、提案させていただきます。

ライセンスタイプBの「ユーザー1人につき2台まで」という条件が少しややこしいので、
これを整理して、
0.「AタイプのライセンスはPCごとにライセンスされる」
0.「Bタイプのライセンスはユーザーごとにライセンスされる」
0.「Bタイプのライセンスは、1ユーザーにつき、PC2台までインストールできる」
という3つの条件として区別して考えるというのはいかがでしょうか。

そして、ライセンス数の在庫に影響するのは1と2であり、3の条件が守られているかどうかを別の問題として考えるとすると、在庫数に関しては以下のように管理できるかと思います。

【テーブル構成】

sql

1/* ユーザー */ 2CREATE TABLE USER( 3 ID INT NOT NULL PRIMARY KEY, 4 NAME VARCHAR(24) 5); 6 7/* パソコン */ 8CREATE TABLE PC( 9 ID INT NOT NULL PRIMARY KEY, 10 SERIAL VARCHAR(4) NOT NULL 11); 12 13/* ソフトウェア */ 14CREATE TABLE SOFTWARE( 15 ID INT NOT NULL PRIMARY KEY, 16 NAME VARCHAR(64), 17 TYPE VARCHAR(1), 18 CNT INT 19); 20 21/* ライセンスタイプ:A */ 22/* どのPCにどのソフトウェアがインストールされているのか */ 23CREATE TABLE R_PC_SOFT( 24 PID INT NOT NULL, /* PC.ID */ 25 SID INT NOT NULL, /* SID.ID */ 26 PRIMARY KEY(PID, SID) 27); 28 29/* ライセンスタイプ:B */ 30/* どのユーザーがどのPCにどのソフトをインストールして使用しているのか */ 31CREATE TABLE R_USER_SOFT( 32 UID INT NOT NULL, /* USER.ID */ 33 PID INT NOT NULL, /* PC.ID */ 34 SID INT NOT NULL, /* SOFTWARE.ID */ 35 PRIMARY KEY(UID, PID, SID) 36);

(FKは省略しましたが、実際には付けた方が良いと思います)

【テストデータ】

sql

1INSERT INTO USER VALUES(1, '田中 一郎'); 2INSERT INTO USER VALUES(2, '山田 太郎'); 3INSERT INTO USER VALUES(3, '太田 光博'); 4INSERT INTO USER VALUES(4, '佐川 和夫'); 5INSERT INTO USER VALUES(5, '太田 明日香'); 6INSERT INTO USER VALUES(6, '篠原 沙希'); 7INSERT INTO USER VALUES(7, '朝霞 寛子'); 8 9INSERT INTO PC VALUES(1, 'H001'); 10INSERT INTO PC VALUES(2, 'H002'); 11INSERT INTO PC VALUES(3, 'H003'); 12INSERT INTO PC VALUES(4, 'H004'); 13INSERT INTO PC VALUES(5, 'H005'); 14INSERT INTO PC VALUES(6, 'H006'); 15 16INSERT INTO SOFTWARE VALUES(1, 'Office2010 Professional', 'A', 5); 17INSERT INTO SOFTWARE VALUES(2, 'Office2010 Personal', 'B', 5); 18INSERT INTO SOFTWARE VALUES(3, 'Office2013 Professional', 'B', 5); 19INSERT INTO SOFTWARE VALUES(4, 'Office365', 'B', 20); 20INSERT INTO SOFTWARE VALUES(5, 'Illustrator CS4', 'A', 4); 21INSERT INTO SOFTWARE VALUES(6, 'Photoshop CS4', 'A', 4); 22INSERT INTO SOFTWARE VALUES(7, 'Dreamweaver CS4', 'A', 4); 23INSERT INTO SOFTWARE VALUES(8, 'InDesign CS4', 'B', 3); 24INSERT INTO SOFTWARE VALUES(9, 'Illustrator CS5', 'B', 6); 25INSERT INTO SOFTWARE VALUES(10, 'Photoshop CS5', 'B', 6); 26INSERT INTO SOFTWARE VALUES(11, 'Dreamweaver CS5', 'B', 6); 27INSERT INTO SOFTWARE VALUES(12, 'InDesign CS5', 'B', 2); 28INSERT INTO SOFTWARE VALUES(13, 'CreativeCloud', 'B', 2); 29INSERT INTO SOFTWARE VALUES(14, 'Acrobat', 'A', 30); 30 31INSERT INTO R_PC_SOFT VALUES(1, 1); 32INSERT INTO R_PC_SOFT VALUES(1, 14); 33INSERT INTO R_PC_SOFT VALUES(3, 14); 34INSERT INTO R_PC_SOFT VALUES(4, 14); 35INSERT INTO R_PC_SOFT VALUES(2, 14); 36INSERT INTO R_PC_SOFT VALUES(6, 14); 37INSERT INTO R_PC_SOFT VALUES(3, 5); 38INSERT INTO R_PC_SOFT VALUES(3, 6); 39INSERT INTO R_PC_SOFT VALUES(3, 7); 40 41INSERT INTO R_USER_SOFT VALUES(2, 3, 13); 42INSERT INTO R_USER_SOFT VALUES(4, 4, 9); 43INSERT INTO R_USER_SOFT VALUES(4, 4, 10); 44INSERT INTO R_USER_SOFT VALUES(4, 4, 11); 45INSERT INTO R_USER_SOFT VALUES(6, 2, 3); 46INSERT INTO R_USER_SOFT VALUES(6, 2, 14); 47INSERT INTO R_USER_SOFT VALUES(1, 6, 3); 48INSERT INTO R_USER_SOFT VALUES(1, 6, 14);

【ライセンス在庫数を確認するSQLサンプル】

sql

1select 2 s.id as "ソフトウェアID", 3 s.name as "名称", 4 s.type as "タイプ", 5 s.cnt as "購入数", 6 ifnull(u.used, 0) as "使用数", 7 ifnull(s.cnt - u.used, 0) as "在庫" 8from software as s 9 left outer join (select sid, count(sid) as used from r_pc_soft group by sid) as u 10 on s.id = u.sid 11where s.type = 'A' 12union 13select 14 s.id as "ソフトウェアID", 15 s.name as "名称", 16 s.type as "タイプ", 17 s.cnt as "購入数", 18 ifnull(u.used, 0) as "使用数", 19 ifnull(s.cnt - u.used, 0) as "在庫" 20from software as s 21 left outer join (select sid, count(sid) as used from r_user_soft group by sid) as u 22 on s.id = u.sid 23where type = 'B' 24order by 1;

【問い合わせ結果】

+----------------------+-------------------------+-----------+-----------+-----------+--------+ | ソフトウェアID | 名称 | タイプ | 購入数 | 使用数 | 在庫 | +----------------------+-------------------------+-----------+-----------+-----------+--------+ | 1 | Office2010 Professional | A | 5 | 1 | 4 | | 2 | Office2010 Personal | B | 5 | 0 | 0 | | 3 | Office2013 Professional | B | 5 | 2 | 3 | | 4 | Office365 | B | 20 | 0 | 0 | | 5 | Illustrator CS4 | A | 4 | 1 | 3 | | 6 | Photoshop CS4 | A | 4 | 1 | 3 | | 7 | Dreamweaver CS4 | A | 4 | 1 | 3 | | 8 | InDesign CS4 | B | 3 | 0 | 0 | | 9 | Illustrator CS5 | B | 6 | 1 | 5 | | 10 | Photoshop CS5 | B | 6 | 1 | 5 | | 11 | Dreamweaver CS5 | B | 6 | 1 | 5 | | 12 | InDesign CS5 | B | 2 | 0 | 0 | | 13 | CreativeCloud | B | 2 | 1 | 1 | | 14 | Acrobat | A | 30 | 5 | 25 | +----------------------+-------------------------+-----------+-----------+-----------+--------+

おそらく、やりたいことはこんな感じなのではと推測したのですが、いかがでしょうか。

ライセンスタイプBの「ユーザー1人につき2台まで」の条件が満たされているかどうかはアプリ側で制御する前提で考えましたが、それをDB側でチェックするのであれば、トリガーでチェックするような形になるかと思います。

投稿2015/11/13 11:49

編集2015/11/13 13:11
pizza

総合スコア27

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

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

smiley-_-smiley

2015/11/16 01:48 編集

返信が遅くなりまして申し訳ありません。 やりたいこととしてはまさにその通りです。 ライセンスの種別ごとに別々の関連テーブルを設けるということですね。 非常にわかりやすいご説明ありがとうございます。 ただ、どうしても理解ができなかったのが、R_USER_SOFTにライセンスタイプAである、Acrobatが含まれている点です。 SQLの内容としては、タイプ別の関連テーブルごとの集計結果を合算しているという認識ですが、どのような意図があるのか、よく考えてみます。
pizza

2015/11/16 04:27

ご指摘の通り、AcrobatはライセンスタイプAなので、R_USER_SOFTに登録すべきではありませんね。これはデータの登録ミスです。失礼しました。
guest

0

ER

ソフトウェア識別番号 | ライセンス番号 | ライセンス連番 | ライセンスタイプ | Microsoft-001-2010-P | 123-456-789-012 | 1 | A | Microsoft-001-2010-P | 123-456-789-013 | 1 | A | Microsoft-001-2010-P | 123-456-789-014 | 1 | A | Microsoft-001-2010-P | 123-456-789-015 | 1 | A | Microsoft-001-2010-P | 123-456-789-016 | 1 | A | Microsoft-002-365 | 123-456-789-017 | 1 | A | Microsoft-002-365 | 123-456-789-017 | 2 | A | Microsoft-002-365 | 123-456-789-017 | 3 | A | Microsoft-002-365 | 123-456-789-017 | 4 | A | Microsoft-002-365 | 123-456-789-017 | 5 | A |
PC識別番号 PC0123456 PC0123457 PC0123458 PC0123459 PC0123460
ソフトウェア利用状況 PC識別番号 | ソフトウェア識別番号 | ライセンス番号 | ライセンス連番 PC0123456 | Microsoft-001-2010-P | 123-456-789-012 | 1 PC0123456 | Microsoft-002-365 | 123-456-789-017 | 1 PC0123457 | Microsoft-001-2010-P | 123-456-789-012 | 1 PC0123458 | Microsoft-002-365 | 123-456-789-017 | 2 PC0123459 | Microsoft-002-365 | 123-456-789-017 | 3
ユーザーテーブル 社員ID | 社員名 00000001 | 山田太郎 00000002 | 佐藤二郎 00000003 | 鈴木三郎
パソコン利用状況テーブル 社員ID |PC識別番号 00000001 |PC0123456 00000002 |PC0123457 00000001 |PC0123458
select ソフトウェア.ソフトウェア識別番号, ソフトウェア利用状況.PC識別番号, 社員ID from ソフトウェア left outer join ソフトウェア利用状況 on ソフトウェア.ソフトウェア識別番号 = ソフトウェア利用状況.ソフトウェア識別番号 left outer join パソコン利用状況テーブル on ソフトウェア利用状況.PC識別番号 = パソコン利用状況テーブル.PC識別番号 left outer join ユーザーテーブル on パソコン利用状況テーブル.社員ID = ユーザーテーブル.社員ID

すみません、結構適当なので他の方のブラッシュアップを期待します。

投稿2015/11/13 09:49

anonymouskawa

総合スコア856

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

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

smiley-_-smiley

2015/11/16 02:39

ありがとうございます。 ちょっと理解しかねる点がありますが、今実際にDBを触れる環境にないため、確認をしたうえであらためてご質問させていただくかと思います。
guest

0

正規化の入門レベルの内容ですが、

1.一人の社員が複数のPCを使用する場合がある

ある社員がどのパソコンを使っているか、複数の社員が同じパソコンを使っている場合のライセンスのカウントを表現する情報(テーブルひとつ追加で済むか?)が必要です。
現状用意できる CREATE TABLE, INSERT文も提示できるとコメントも付きやすいでしょう。
PRIMARY KEYに相当する列がIDですと誤解し易いので、列名ひとつとっても分かり易いネーミングを考えてください。

投稿2015/11/13 09:41

Orlofsky

総合スコア16415

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

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

smiley-_-smiley

2015/11/16 02:45

初歩的な質問で申し訳ありません。 >ある社員がどのパソコンを使っているか、複数の社員が同じパソコンを使っている >場合のライセンスのカウントを表現する情報(テーブルひとつ追加で済むか?)が >必要です。 関連テーブルが必要だと考えたのですが、複数の意味を持つ関連テーブルになってしまうと考えたため、わからなくなってしまいました。 考え方をまとめている状態での質問だったため、具体的なテーブル構造まで作成しておりません。 皆様からいただいたアドバイスからあらためて考えてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問