顧客別品名マスタ(以下、品名M)と顧客品名変更履歴ファイル(以下、履歴F)があります。
(履歴Fは品名Mを変更する都度、レコードが増えていきます。)
※履歴レコードは品名Mに対して存在しない場合もあります
<ユニークキー>
品名M:顧客コード、品名コード
履歴F:顧客コード、品名コード、No
以下の条件でSQLを作成したのですが、問題ないでしょうか?
他に良い案があれば教えて下さい。
<絞込条件>
・指定した顧客のみの品名を絞込む
・品名Mとリンクする履歴Fのレコードが存在する場合、最新レコードのみ結合する
(使用DB:SQLSERVER)
SELECT 品名,変更者,変更日,変更理由 FROM 品名M LEFT JOIN 履歴F ON 品名M.顧客コード = 履歴F.顧客コード AND 品名M.品名コード = 履歴F.品名コード AND 履歴F.No = (SELECT MAX(No) FROM 履歴F R2 WHERE 品名M.顧客コード = R2.顧客コード AND 品名M.品名コード = R2.品名コード GROUP BY R2.顧客コード,R2.品名コード)
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
SQLServerの分析関数の使用例の「4. 最大値の行の取得」
https://oraclesqlpuzzle.ninja-web.net/sqlserver2008-sql1-olap.html#1-4
を見ながら作ってみました :-)
sql
1with tmp履歴F as( 2select 顧客コード,品名コード 3 from (select 顧客コード,品名コード,No, 4 max(No) over(partition by 顧客コード,品名コード) as MaxNo 5 from 履歴F) a 6 where No = MaxNo) 7select 品名,変更者,変更日,変更理由 8 from 品名M Left Join tmp履歴F 9 on 品名M.顧客コード = tmp履歴F.顧客コード 10 AND 品名M.品名コード = tmp履歴F.品名コード
Outer Applyを使う方法もあるようですが、
まだ勉強中なのであった。
投稿2016/09/03 05:20
編集2019/03/12 06:36総合スコア1147
0
ベストアンサー
つっこんだので私なりの回答
sql
1SELECT M1.品名 2 , F1.変更者 3 , F1.変更日 4 , F1.変更理由 5FROM 6 品名M M1 7 LEFT JOIN 履歴F F1 8 ON M1.顧客コード = F1.顧客コード 9 AND M1.品名コード = F1.品名コード 10 -- グルーピング項目で絞ってるため GROUP BY 不要 11 -- LEFT JOIN の条件として指定することで 存在しない場合でも マスターは表示される 12 AND F1.No = ( 13 SELECT MAX(F2.No) 14 FROM 履歴F F2 15 WHERE F2.顧客コード = F1.顧客コード 16 AND F2.品名コード = F1.品名コード 17 ) 18;
ふと思った別案 SQLServer で対応可能かは知らないが
sql
1WHERE NOT EXISTS ( 2 SELECT 1 3 FROM 履歴F F2 4 WHERE F2.顧客コード = F1.顧客コード 5 AND F2.品名コード = F1.品名コード 6 AND F2.No > F1.NO 7)
でも行けそうな予感
投稿2016/09/02 03:39
編集2016/09/03 02:01退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/09/02 04:38
2016/09/02 05:21
0
パフォーマンス上問題が発生していないのであれば、
掲示されておられるコードが一番やりたいことを明確に表現したクエリとなっていますので特に変更はいらないかと思われます。
敢えて何か助言するとしましたら、
履歴テーブルが2度出てくるのでテーブル別名を付けてあげるとか、
SELECT句のカラムにどちらのテーブルから取得しているかが一目で分かるようにテーブル名、またはテーブル別名を指定した方が親切かなといったぐらいですかね。
以下蛇足ですが、
仮に上記のクエリでパフォーマンス上に問題が出ているなどがある場合は、
顧客コード、品名コード、履歴No.の最大値を取得するサブクエリを、
外部結合でくっつけるという方法の方が速度が出るかもしれません。
(※こればかりは実行計画の違いがでるかどうか確認しないと最終的な判断はできませんが^^;)
SQL
1SELECT 2 M.品名 3, H.変更者 4, H.変更日 5, H.変更理由 6FROM 7 品名M M 8 LEFT JOIN( 9 SELECT 10 H1* 11 H2.MAX_NO 12 FROM 13 履歴F H1 14 INNER JOIN ( 15 SELECT 16 顧客コード 17 , 品名コード 18 , MAX(NO) AS MAX_NO 19 FROM 20 履歴F 21 GROUP BY 22 顧客コード 23 , 品名コード 24 ) H2 25 ON H1.顧客コード = H2.顧客コード 26 AND H1.品名コード = H2.品名コード 27 AND H1.NO = H2.MAX_NO 28 ) H 29 ON M.顧客コード = H.顧客コード 30 AND M.品名コード = H.品名コード
書いてる途中にこっちの方がダメそうな気がしてきた・・・
投稿2016/09/01 11:06
総合スコア1636
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/09/02 00:22
0
SQL Serverの微妙な文法の違いはよくわかりませんが
私はこんな感じでよくやります
SQL
1SELECT 品名,変更者,変更日 2FROM 品名M 3LEFT JOIN 履歴F 4ON 品名M.顧客コード = 履歴F.顧客コード 5AND 品名M.品名コード = 履歴F.品名コード 6AND (履歴F.No,履歴F.顧客コード,履歴F.品名コード) IN 7(SELECT MAX(No),顧客コード,品名コード FROM 履歴F 8GROUP BY 顧客コード,品名コード)
#結局
冗長になりますがこうなんでしょうね・・・
SQL
1SELECT 品名,変更者,変更日 2FROM 品名M 3LEFT JOIN 4(SELECT 変更者,変更日,履歴F.顧客コード,履歴F.品名コード 5FROM 履歴F INNER JOIN 6(SELECT MAX(No) AS No,顧客コード,品名コード FROM 履歴F 7GROUP BY 顧客コード,品名コード) AS SUB 8ON 履歴F.No=SUB.No 9AND 履歴F.顧客コード=SUB.顧客コード 10AND 履歴F.品名コード=SUB.品名コード) AS SUB 11ON 品名M.顧客コード = SUB.顧客コード 12AND 品名M.品名コード = SUB.品名コード ;
ちなみに、INの複数指定ができないということはUSINGの複数してもできないのでしょうか?
SQL
1SELECT 品名,変更者,変更日 2FROM 品名M 3LEFT JOIN 4(SELECT 変更者,変更日,顧客コード,品名コード 5FROM 履歴F INNER JOIN 6(SELECT MAX(No) AS No,顧客コード,品名コード FROM 履歴F 7GROUP BY 顧客コード,品名コード) AS SUB 8USING(No,顧客コード,品名コード)) AS SUB 9USING(顧客コード,品名コード);
投稿2016/09/01 03:57
編集2016/09/02 03:39総合スコア114767
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/09/01 04:04
2016/09/01 04:04
2016/09/01 08:19
2016/09/01 08:27
2016/09/02 00:05
2016/09/02 03:18
2016/09/02 03:42
2016/09/02 11:21
0
問題ありません。
HAVING句やEXISTS句や
ORDER BY + Limit 1を使って抽出も可能ですが、
私はseesaajira-さんが記載してあるSQL文が好みです。
強いて言えば、JOIN の向きを逆にするかな、というくらいです。
SQL
1SELECT M1.品名 2 , F1.変更者 3 , F1.変更日 4 , F1.変更理由 5FROM 履歴F F1 6 LEFT JOIN 品名M M1 ON ( 7 M1.顧客コード = F1.顧客コード 8 AND M1.品名コード = F1.品名コード 9 ) 10WHERE F1.No = ( 11 SELECT MAX(F2.No) 12 FROM 履歴F F2 13 WHERE F2.顧客コード = F1.顧客コード 14 AND F2.品名コード = F1.品名コード 15 GROUP BY F2.顧客コード 16 , F2.品名コード 17 ) 18;
投稿2016/09/01 03:49
編集2016/09/01 04:04総合スコア760
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/09/01 04:09
2016/09/01 04:14 編集
2016/09/01 04:20
2016/09/01 04:22
退会済みユーザー
2016/09/02 03:25
2016/09/03 01:52
2016/09/03 03:42
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2016/09/03 05:28
2016/09/03 05:46
2016/09/05 00:54