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

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

解決済

2回答

2173閲覧

SQL文をもっとよくしたい

k499778

総合スコア599

MySQL

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

SQL

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

0グッド

0クリップ

投稿2018/06/27 13:23

編集2018/06/28 23:46

質問があるのですが、
以下のSQLはどのような書き方にすればもっとよくなるでしょうか?

ちなみにORマッパーはDomaを使っています

要件は以下です。
「ログインユーザーが所属する店舗(store_mst)あるいは、そのチェーン店(groupstore_mst)に紐づく商品分類タグ(tag_mst)で、その商品分類タグのWEB表示(tag_mst.display_flg = 1)件数が合わせて5件を超える店舗IDを取得する」

スキーマ構成としては以下です。

商品分類タグマスタ(tag_mst) ・tag_id(PK) ・store_id ・groupstore_id ・display_flg 店舗マスタ(store_mst) ・store_id(PK) ・groupstore_id ・store_name チェーン店マスタ(groupstore_mst) ・groupstore_id(PK) ・groupstore_name

今SQLで以下ようなクエリを作成しています。Domaの書き方になっています。引数はログインユーザーのstoreIdです。

SQL

1SELECT 2 T5.store_id 3FROM 4 ( 5 SELECT 6 T1.store_id, 7 ( 8 SELECT COUNT(*) 9 FROM 10 tag_mst T2 11 WHERE 12 T2.store_id = T1.store_id AND T2.display_flg = 1 13 GROUP BY 14 T2.store_id 15 ) +( 16 SELECT COUNT(*) 17 FROM 18 tag_mst T3 19 WHERE 20 T3.groupstore_id =( 21 SELECT 22 T4.groupstore_id 23 FROM 24 store_mst T4 25 WHERE 26 T4.store_id = T1.store_id 27 ) AND T3.display_flg = 1 28) AS cnt 29FROM 30 tag_mst T1 31WHERE 32 store_id = /*storeId*/101 33GROUP BY 34 T1.store_id 35) T5 36WHERE 37 cnt > 5 38

もう少し良い書き方がしたいのですが、アドバイス頂けないでしょうか?
よろしくお願い致します。


補足

sql

1CREATE TABLE `tag_mst` ( 2 `tag_id` int(11) NOT NULL, 3 `store_id` int(11) DEFAULT NULL, 4 `groupstore_id` int(11) DEFAULT NULL, 5 `display_flg` int(11) DEFAULT 0 6) ENGINE=InnoDB DEFAULT CHARSET=latin1; 7 8CREATE TABLE `store_mst` ( 9 `store_id` int(11) NOT NULL, 10 `groupstore_id` int(11) DEFAULT NULL, 11 `store_name` text 12) ENGINE=InnoDB DEFAULT CHARSET=latin1; 13 14 15INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('1', '101', NULL, '1'); 16INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('2', '101', NULL, '1'); 17INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('3', '101', NULL, '1'); 18INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('4', '101', NULL, '1'); 19INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('5', '101', NULL, '1'); 20INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('6', '101', NULL, '1'); 21INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('11', NULL, '201', '1'); 22INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('12', NULL, '201', '1'); 23INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('13', NULL, '201', '1'); 24INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('14', NULL, '201', '1'); 25INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('15', NULL, '201', '1'); 26INSERT INTO `tag_mst` (`tag_id`, `store_id`, `groupstore_id`, `display_flg`) VALUES ('16', NULL, '201', '1'); 27 28INSERT INTO `store_mst` (`store_id`, `groupstore_id`, `store_name`) VALUES ('101', '201', 'name'); 29 30ALTER TABLE `store_mst` ADD UNIQUE(`store_id`);

補足2

伝わりづらいようなので要件の説明を追加します。

チェーン店で設定した商品分類タグはそれに紐づく店舗でも共通して画面表示されるので、チェーン店の共通タグと店舗個別のタグを足した合計が5件を超えるstore_idを取得したい

というものになります。回答者様のコメント欄にも詳しく記載してますので併せてご覧下さい。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2018/06/27 14:23

各テーブルのCREATE文とサンプルデータのINSERT文を提示してください。
sazi

2018/06/27 15:15

そもそも動作するSQLじゃないし、要件にあるgroupstore_mstも出現していない。
sazi

2018/06/27 15:31

失礼。groupstore_mstは不要そう
k499778

2018/06/27 15:59

groupstore_mstは話の流れ上書きました。DDL,DML作成しました。
sazi

2018/06/27 16:09

質問にあるSQLはエラーにはならないのですか? from ()+()なんて記述は初めて見たのですが。
k499778

2018/06/27 16:18

()+()の書き方は問題なく動きます
sazi

2018/06/27 16:28

サブクエリーで件数加算というなら分かるけど from ()+()って・・・()の数もあって無いし、どこか記述が漏れてませんか?
k499778

2018/06/27 16:49

数えましたが()の数が4つで漏れていないと思います
退会済みユーザー

退会済みユーザー

2018/06/27 16:55

提示されたCREATE,INSERTで提示されたそもそものSQLがエラーで動きません。正確な情報を提示してください。
sazi

2018/06/27 17:38 編集

()の数は合いましたが文法的にエラーですので、もう一度確認してください。 エラーのSQLだと、後学者に取ってこの記事自体が成り立たないので
m.ts10806

2018/06/28 00:04

「よくする」の落としどころが明確になってないと永久に解決しない気がします。
k499778

2018/06/28 00:43

スッキリしたSQL文にしたい。パフォーマンスチューニングをしたいですね。
k499778

2018/06/28 00:45

今要件がうまく伝わっておらず、想定した結果が返ってきていないのでそれでBAつけあぐねています。saziさんのアドバイスの方向性でかなり満足しています。あとは想定した結果さえ取れれば。saziさんのコメントに悩みんでいるところの部分は記載しています。
m.ts10806

2018/06/28 00:47

コメント部分だけだと共有されないので要件が変わってきている部分、修正事項については質問本文に反映しておくようにしてください(既にされているかもしれませんが、念のため) もっといえば、タイトルは変えたほうがいいかも。
arasi

2018/06/28 01:12

質問とはかんけいないが InnoDB DEFAULT CHARSET=latin1 にしていて文字化けしないのか?
guest

回答2

0

ベストアンサー

質問のSQLを分析します

SQL

1SELECT T5.store_id 2FROM ( 3 SELECT T1.store_id 4 , ( 5 SELECT COUNT(*) FROM tag_mst T2 6 WHERE T2.display_flg = 1 AND T2.store_id=T1.store_id GROUP BY T2.store_id 7 ) + ( 8 SELECT COUNT(*) FROM tag_mst T3 9 WHERE T3.display_flg = 1 AND T3.groupstore_id=( 10 SELECT T4.groupstore_id FROM store_mst T4 WHERE T4.store_id = T1.store_id 11 ) 12 ) 13 AS cnt 14 FROM tag_mst T1 15 WHERE store_id = /*storeId*/101 16 GROUP BY T1.store_id 17) T5 18WHERE cnt > 5

指定した店舗の件数が>5の結果しか返却しないので、これでは要件満たせていませんね。

店舗マスタと商品分類マスタを結合(or条件がポイント)し、店舗別の共通分類を含めた一覧としてそれを集計する

SQL

1select str.store_id 2from store_mst str inner join tag_mst tag 3 on str.groupstore_id=tag.groupstore_id or str.store_id=tag.store_id 4where tag.display_flg = 1 5 and str.groupstore_id in ( 6 select groupstore_id from store_mst where store_id=/*storeId*/101 7 ) 8group by str.store_id 9having count(*)>5

質問のSQLが要件を満たしている場合、指定した店舗のみの状況は件数のみで判断できるので、以下のようにすると簡潔になります。

SQL

1select count(*) 2from store_mst str inner join tag_mst tag 3 on str.groupstore_id=tag.groupstore_id or str.store_id=tag.store_id 4where tag.display_flg = 1 5 and str.store_id=/*storeId*/101

投稿2018/06/27 15:38

編集2018/06/28 04:16
sazi

総合スコア25173

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

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

k499778

2018/06/27 16:10 編集

回答ありがとうございます。またこちらでもいろいろ試してから返答致します。
k499778

2018/06/27 16:24

一行目のstore_idをtag_mstから取得しているのでnullで返ってきてしまう場合があります。(groupstore_idで条件があった場合) それに対してうまく対処する方法はないでしょうか?
sazi

2018/06/27 16:33 編集

データ確認していなかったのでちょっと待って下さい。
k499778

2018/06/27 16:39

はい。ありがとうございます。 あと誤解を生んでしまったかもしれませんが、orのイメージでした。 (前)ログインユーザーが所属する店舗(store_mst)"と"そのチェーン店(groupstore_mst)に紐づく (今)ログインユーザーが所属する店舗(store_mst)"あるいは"、そのチェーン店(groupstore_mst)に紐づく 少しわかりやすく書き換えました。ご配慮いただけると助かります。
k499778

2018/06/27 16:42

パターン1に関しては現行のままだとエラーになり、以下のようにすると動きました。 ただ想定される101が返されず,nullが返されました。 ANYをつけました。 select store_id from tag_mst where display_flg = 1 and groupstore_id = ANY(select groupstore_id from store_mst where store_id=101) group by store_id having count(*)>5
sazi

2018/06/27 16:54

要件として店舗IDを求めるとありますが、店舗IDは指定の条件なので、ややこしくなるだけなので、件数を返却するものとしました。その件数で判定すれば良いでしょうし。
k499778

2018/06/27 16:55

phpMyAdminで実行しているのですがエラーになってしまいます。(#1242 - Subquery returns more than 1 row) なのでANYをサブクエリの前に入れて実行しました。 想定通りの結果が返ってきています。 他のデータも入れて試してみます。 select store_id from tag_mst where display_flg = 1 and store_id in ( select store_id from store_mst where groupstore_id = ANY( select groupstore_id from store_mst where store_id=/*storeId*/5100 ) ) group by store_id having count(*)>5
sazi

2018/06/27 17:06

確認しているデータが違うからですね。 select groupstore_id from store_mst where store_id=/*storeId*/5100 これが複数件返却されるのですか? 店舗マスタで店舗IDでユニークじゃないって・・・
sazi

2018/06/27 17:10

しかも、SQL変わってて、ORじゃなくなってるし・・・
sazi

2018/06/27 17:27

ログインユーザーが所属する店舗が含まれるチェーン店のうち、商品件数が>5の店舗ということ?
sazi

2018/06/27 17:36

コメントを見るとそのようなので、修正しました。
k499778

2018/06/27 22:40

ALTER TABLE `store_mst` ADD UNIQUE(`store_id`);にしてデータを整理すると,ANYをつけなくてもエラーが起きなくなりました。質問の投稿にも追加しておきます。 ありがとうございます。
k499778

2018/06/28 00:42

SQL文の方試してみたのですが、 想定の結果がやはり返ってきませんでした。 ログインユーザーの店舗IDに紐づくチェーン店IDのタグ(where tag_mst.groupstore_id= 201)が5件超える場合もその店舗IDを取得したいです。 例えば where tag_mst.groupstore_id= 201 のものが6件、where tag_mst.store_id= 101 のものが0件 だとしても合計5件を超えるのでstore_id101を取得します。 今だと絞りに絞っているので、そういった場合取れてきません。 そこも考慮に入れて頂けると助かります。
sazi

2018/06/28 01:11

tag_mstのstore_idが設定されているもの ・店舗ごとの商品分類 tag_mstのgroupstore_idが設定されているもの ・チェーン店の共通商品分類 に対して、指定した店舗の属するチェーン店で上記分類が>5の条件の店舗 (チェーン店共通商品分類>5なら結局そのチェーン店店舗全て) という仕様ですか? 上記仕様を確認する為にも、質問のSQLをエラーが無い状態にしてと言っているんですが
k499778

2018/06/28 01:23

失礼しました。SQLを修正致しましたのでご確認頂ければと思います。
k499778

2018/06/28 01:27

そうですね。仕様としてもそれで合っています。なのでチェーン店が5件超えていればそれに紐づく店舗IDは全て取得ですね。 チェーン店で設定した商品分類タグはそれに紐づく店舗でも共通して画面表示されるので、チェーン店の共通タグと店舗個別のタグを足した合計が5件を超えるstore_idを取得したいです。お手数ですがお願いできたらと思います。
sazi

2018/06/28 02:03

全面的に回答修正
k499778

2018/06/28 03:59

ありがとうございます。すごく助かりました。最後までお付き合い頂きありがとうございました。感謝しています
sazi

2018/06/28 04:05

性能はどのくらい改善されました?
k499778

2018/06/28 04:57

性能としてあまり大きな変化は見られましんでしたが、コードが圧倒的にスッキリしました。大量データのテストはまだなのでその時また性能を感じたいと思います。
guest

0

SQLの実行にはSQLの中で使っているテーブルの定義が必要ですから、各テーブルのCREATE TABLE文を、動作確認できるだけの(今回は [件数が合わせて5件を超える店舗ID]) のデータのINSERT文も質問にあった方がコメントが付き易いです。

以下、質問を訂正されては?

2カ所全角の空白が入っています。

□T5.store_id
store_id = /storeId/□5100

同じテーブルを何度もSELECTするのなるべく避けた方がパフォーマンスが良いです。

今回の抽出条件に

store_id = 5100

とありますが、これは最初(インランビューの中で)に対象データをしぼった方がパフォーマンスが良いです。

メンテの為にもテーブルの別名であろうとどのテーブルであるかわかり易く

tag_mst T2
tag_mst TM

などとされては?

投稿2018/06/27 14:24

Orlofsky

総合スコア16415

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

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

k499778

2018/06/27 16:10

回答ありがとうございます。またこちらでもいろいろ試してから返答差し上げたいと思います。
Orlofsky

2018/06/27 19:34

全角の空白がもう1つ残っています。 > □T5.store_id メモ帳でコードを書いているならサクラエディタを使っては? http://monaski.hatenablog.com/entry/2015/06/06/232751 > `display_flg` int(11) DEFAULT '0' 数値はシングルクォートで囲まないでください。 INSERT文も直してください。
k499778

2018/06/27 23:24

修正しました。ご指摘ありがとうございます。
Orlofsky

2018/06/28 01:02

ちゃんと読んでください。 INSERT文が直っていません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問