SlideShare a Scribd company logo
Copyright 2016-2018 G1Systems Inc.
ストアドプロシージャを使っ
た開発について
中級者向け
1
Copyright 2016-2018 G1Systems Inc.
はじめに
SQLおじさんですw
SQLServerだけではなく、RDB全般について
専門的に仕事を請けています。
金融から、製造業、ネットゲームまで、オー
ルランドに対応しております。
その中で、今日はストアドプロシージャを
使った開発についてお話します。
2
Copyright 2016-2018 G1Systems Inc.
前回の復習
3
Copyright 2016-2018 G1Systems Inc.4
例題
すべての生徒のリストに、特待生マスタの削除フラグが 0の
特待生ランクを出力してください。
2 C
生徒ID ランク
3 A
10 B
33 C
40 B
48 C
1石野 扶樹
ID氏名
2岩崎 研二
3岩間 竜也
4上野 浩介
5岡崎 雅之
6岡島 慶二
生徒マスタ 特待生マスタ
1
削除フラグ
0
0
0
0
0
Copyright 2016-2018 G1Systems Inc.
解答
5
SELECT a.氏名, b.ランク
FROM 生徒マスタ a
LEFT OUTER JOIN 特待生マスタ b
ここに結合条件を追加
これを出力
したくない
生徒マスタ 特待生マスタ
2 C
生徒ID ランク
3 A
10 B
33 C
40 B
48 C
1石野 扶樹
ID氏名
2岩崎 研二
3岩間 竜也
4上野 浩介
5岡崎 雅之
6岡島 慶二
1
削除フラグ
0
0
0
0
0
Copyright 2016-2018 G1Systems Inc.
これはNG!
6
SELECT
a.氏名, b.ランク
FROM 生徒マスタ a
LEFT OUTER JOIN 特待生マスタ b
ON a.ID = b.生徒ID
WHERE
b.削除フラグ = 0;
Copyright 2016-2018 G1Systems Inc.
なぜNGか?
7
WHERE 削除FLAG = 0 では、
NULL = 0 となる、 のレコードが出力できない。
1行だけになってしまう。
← NULL = 0 は False
← NULL = 0 は False
← NULL = 0 は False
生徒マスタ 特待生マスタ
2 C
生徒ID ランク
3 A
(4) NULL
(5) NULL
(6) NULL
1石野 扶樹
ID氏名
2岩崎 研二
3岩間 竜也
4上野 浩介
5岡崎 雅之
6岡島 慶二
1
削除フラグ
0
NULL
NULL
NULL ← NULL = 0 は False
10 B
33 C
40 B
0
0
0
(1) NULL NULL
← 1= 0 は False
Copyright 2016-2018 G1Systems Inc.
サブクエリーは意味は正しいけれど……
8
SELECT
a.氏名, b.ランク
FROM 生徒マスタ a
LEFT OUTER JOIN
(SELECT * FROM 特待生マスタ
WHERE 削除フラグ = 0) b
ON a.ID = b.生徒ID;
Copyright 2016-2018 G1Systems Inc.
正しくはこうする!
9
SELECT
a.氏名, b.ランク
FROM 生徒マスタ a
LEFT OUTER JOIN 特待生マスタ b
ON a.ID = b.生徒ID
AND 0 = b.削除フラグ;
Copyright 2016-2018 G1Systems Inc.
イメージにすると……
10
生徒マスタ a 特待生マスタ b
a.ID = b.生徒ID
AND b.削除フラグ = 0
a.ID = b.生徒ID
AND b.削除フラグ <> 0
a.ID <> b.生徒ID
AND b.削除フラグ = 0
a.ID <> b.生徒ID
AND b.削除フラグ <> 0
b.削除フラグ = 0 で
全体を削りたい訳ではない。
Copyright 2016-2018 G1Systems Inc.
SQLServer や Oracle などはサブクエリを直す
SQLServer や Oracle などの商用DBは、
11
SELECT
a.氏名, b.ランク
FROM 生徒マスタ a
LEFT OUTER JOIN
(SELECT * FROM 特待生マスタ
WHERE 削除フラグ = 0) b
ON a.ID = b.生徒ID;
SELECT
a.氏名, b.ランク
FROM 生徒マスタ a
LEFT OUTER JOIN 特待生マスタ b
ON a.ID = b.生徒ID
AND 0 = b.削除フラグ;
パースの段階で SQL を直してから実行します。
直してくれない RDBMS は めっちゃ遅い!
特にハッシュジョインがない MySQL は OUT!
Copyright 2016-2018 G1Systems Inc.
右に置いたテーブルがWHERE句に入るとバグ
12
SELECT
a.氏名, b.ランク
FROM 生徒マスタ a
LEFT OUTER JOIN 特待生マスタ b
ON a.ID = b.生徒ID
WHERE
b.ランク = 'A';
外部結合を打消してしまう。
どちらを意図しているのか、
ソースからは分からない。
Copyright 2016-2018 G1Systems Inc.
ところが、例えば、WordPress 4.9.4 での例
if ( $post_status_join ) {
$join .= " LEFT JOIN {$wpdb->posts} AS p2 ON
({$wpdb->posts}.post_parent = p2.ID)";
foreach ( $statuswheres as $index => $statuswhere ) {
$statuswheres[$index] =
"($statuswhere
OR ({$wpdb->posts}.post_status = 'inherit’
AND ".str_replace( $wpdb->posts, 'p2', $statuswhere ) . "))";
}
}
$where_status = implode( ' OR ', $statuswheres );
if ( ! empty( $where_status ) ) {
$where .= " AND ($where_status)";
} ※ class-wp-query.php
13
Copyright 2016-2018 G1Systems Inc.
WordPress 4.9.4 は、最後に LEFT JOIN に変換
/** Generates SQL clauses to be appended to a main query.
-- 中略 --
public function get_sql( $type, $primary_table, ……
-- 中略 --
/* If any JOINs are LEFT JOINs (as in the case of NOT EXISTS), then all JOINs should be
LEFT. Otherwise posts with no metadata will be excluded from results. */
-- 中略 --
if ( false !== strpos( $sql['join'], 'LEFT JOIN' ) ) {
$sql['join'] = str_replace( 'INNER JOIN', 'LEFT JOIN', $sql['join'] );
}
-- 中略 -- ※ class-wp-meta-query.php
14
Copyright 2016-2018 G1Systems Inc.
一応、Word Press がやっている変換意図を解説
15
生徒マスタ 特待生マスタ
2 C
生徒ID ランク
3 A
(4) NULL
(5) NULL
(6) NULL
1石野 扶樹
ID氏名
2岩崎 研二
3岩間 竜也
4上野 浩介
5岡崎 雅之
6岡島 慶二
1
削除フラグ
0
NULL
NULL
NULL
10 B
33 C
40 B
0
0
0
(1) NULLNULL
ランク名称マスタ
学業特待生AA
名称ランク
学業特待生BB
スポーツ特待生C
こちらINNER JOIN にすると、
B・Cに一致するものがない
ため、外部結合を打消してし
まう。こちらを LEFT JOIN
Copyright 2016-2018 G1Systems Inc.
ここまでのまとめ
何年か前、「すべての変数を Static で宣言したらしっく
りくる」とブログに書いて炎上した人がいました。
しかし、すべての JOIN を LEFT でというのは、まったく
珍しくありません。新人にそう教育している大手企業をい
くつも知っています。
どちらも間違っていますが、どちらが実害が大きいかは明
らかです。
LEFT 決め打ちは、「すべての変数を Static で宣言」よ
り技術レベルが低い。と心得ましょう。
16
Copyright 2016-2018 G1Systems Inc.
WHERE句は論理演算の塊
17
Copyright 2016-2018 G1Systems Inc.
論理演算を復習しよう!
AND(論理積)は掛け算、OR(論理和)は足し算
True は 1(0以外)
False は 0
として、簡単な数式に直して考えてみましょう。
もちろん、演算の順序も掛け算(AND)が先です。
T and T and F and T and T and T
= 1 × 1 × 0 × 1 × 1 × 1 = 0 (False)
F or F or F or T or F or F
= 0 + 0 + 0 + 1 + 0 + 0 = 1 (True)
18
Copyright 2016-2018 G1Systems Inc.
因数分解、展開も数式と同じ
(a × b) + (a × c)
= a × (b + c)
(a AND b) OR (a AND c) 男性で日本人、または、男性でアメリカ人
= a AND (b OR c) 男性で、日本人、または、アメリカ人
これらは、SQLに限らずどんな言語でも必要なので、息をす
るのと同じレベルでできるようになってください。
19
Copyright 2016-2018 G1Systems Inc.
SQLの動的生成を避ける!
ただし、Oracleではできません!
20
Copyright 2016-2018 G1Systems Inc.
SQLの動的生成を避ける1
21
keyの範囲を指定してレコードを検索する処理を考える
画面
開始値
終了値
1
10
WHERE句
開始値・終了値の有無に応じて
4種類のWHERE句が必要になる
開始値 終了値
なしなし なし
ID >= 開始値あり なし
ID <= 終了値なし あり
ID >= 開始値 AND ID <= 終了値あり あり
Copyright 2016-2018 G1Systems Inc.
sqlWhere = "";
if( 開始値 != null){
sqlWhere = "WHERE ";
sqlWhere += " col1 >= " + 開始値;
}
if( 終了値 != null){
if(sqlWhere == ""){
sqlWhere += " WHERE ";
} else {
sqlWhere += " AND ";
}
sqlWhere += " col1 <= " + 終了値;
}
if(sqlWhere != ""){
sql += sqlWhere;
}
22
古典的なSQL文生成ロジックを書くと……
Copyright 2016-2018 G1Systems Inc.
sqlWhere = " WHERE 1 = 1 ";
if( 開始値 != null){
sqlWhere += " AND col1 >= @開始値";
// パラメータ(param)を生成して
Paramaters.Add(param);
}
if( 終了値 != null){
sqlWhere += " AND col1 <= @終了値";
// パラメータ(param)を生成して
Paramaters.Add(param);
}
sql += sqlWhere;
23
SQL文生成ロジックを書くと……
Copyright 2016-2018 G1Systems Inc.
実は、動的生成は不要です。
SELECT *
FROM table_a
WHERE
(col1 >= @開始値 OR @開始値 IS NULL)
AND (col1 <= @終了値 OR @終了値 IS NULL);
24
※ 当然、FROM句、HAVING句でも使えます!
Copyright 2016-2018 G1Systems Inc.
パースされると消える!
25
(col1 >= @開始値 OR @開始値 IS NULL)
@開始値がNULL @開始値が1000
(col1 >= NULL OR NULL IS NULL) (col1 >= 1000 OR 1000 IS NULL)
(col1 >= NULL OR True) (col1 >= 1000 OR False)
意味がないので消える (col1 >= 1000)だけが残る
Copyright 2016-2018 G1Systems Inc.
SQLServerは、RECOMPILE指定する
SELECT *
FROM テーブル
WHERE
(col1 = @検索値1 OR @検索値1 IS NULL)
AND (col2 = @検索値2 OR @検索値2 IS NULL)
OPTION(RECOMPILE);
とすれば、毎回、パースからやり直してくれる。
26
Copyright 2016-2018 G1Systems Inc.
更には……(任意の OR条件を追加)
27
画面
開始値
終了値
1
10
または
区分 A
SELECT * FROM table_a
WHERE
((col1 >= @開始値 OR @開始値 IS NULL)
AND (col1 <= @終了値 OR @終了値 IS NULL))
OR (col2 = @区分 AND @区分 IS NOT NULL)
※ 当然、FROM句、HAVING句でも使えます!
Copyright 2016-2018 G1Systems Inc.
更には……
28
画面
検索値
比較演算子
1
<=
SELECT * FROM table_a
WHERE
(col1 = 検索値 OR @比較演算子 <> "=")
AND (col1 >= 検索値 OR @比較演算子 <> ">=")
AND (col1 <= 検索値 OR @比較演算子 <> "<=")
AND (col1 > 検索値 OR @比較演算子 <> ">")
AND (col1 < 検索値 OR @比較演算子 <> "<")
※ 当然、FROM句、HAVING句でも使えます!
▼
Copyright 2016-2018 G1Systems Inc.
LEFT JOIN を切り替えるなら
29
画面
過去特待生だった
らそれも表示
@区分 が 1 なら削除フラグが立っていても出力し、
以外ならしない。
SELECT
a.氏名, b.ランク
FROM 生徒マスタ a
LEFT OUTER JOIN 特待生マスタ b
ON a.ID = b.生徒ID
AND (0 = b.削除フラグ OR @区分 = 1);
する
しない
Copyright 2016-2018 G1Systems Inc.
まとめ – SQLの動的生成は要らない
弊社で開発した ERP のスクラッチ案件
見積、受注、発注、売上、請求、入金、部品表、在庫引当、
入庫、出荷、棚卸、作業費、外注管理、交通費、利益管理
全て、ストアドプロシージャで作成。
SQLの動的生成はゼロ!
30
Copyright 2016-2018 G1Systems Inc.
実演します
SQLのイメージの仕方
31
Copyright 2016-2018 G1Systems Inc.
MVCは間違っている
32
Copyright 2016-2018 G1Systems Inc.
ヒットするデータが少ないと予想したとき
33
インデックスを抽出して
プライマリーキー(実データ)
をループしながら結果セットを
作っていきます。
Copyright 2016-2018 G1Systems Inc.
ヒットするデータが少ないと予想したとき
RowIDLists[] rowIDs New RowIDLists[] ; // ヒットしたもの
RetrunRows[] retRows New RetrunRows[] ; // 戻すレコード
rowIDs = IX_売上日.getRange(#日付F#, #日付T#); //日付範囲
for(RowID rowID:rowIDs){
// 計算処理
retRows.add(売上.getRow(rowID));
}
Return retRows;
34
Copyright 2016-2018 G1Systems Inc.
MVCは1980年代のスタンドアローン向け概念
35
スタンドアローンPC
View
Control
Model
Copyright 2016-2018 G1Systems Inc.
DBサーバ
Webに適用するとインピーダンスミスマッチ
36
WEBサーバ APサーバ
View
Control
Model
SQL
SQLは界面が
合わない異物
Copyright 2016-2018 G1Systems Inc.
O/Rマッパで解消
DBサーバWEBサーバ APサーバ
View
Control
Model
SQL
O/Rマッパで
異物を覆う
Copyright 2016-2018 G1Systems Inc.
本来はDBを疎結合にすべき(異物は隠蔽すべき)
38
DBサーバWEB
サーバ
APサーバ
View
Control
Model
RDBMS
DBサーバ
RDBMS
Inter
face
Inter
face
Copyright 2016-2018 G1Systems Inc.
MVCは1980年代に生まれた概念
MVCは1980年代に生まれた概念で、Webも、DBも意識
して作られていません。
「疎結合にすべき」という概念なのに、メモリー空間も、
処理構造も全く違う RDBMS を「オブジェクト指向言語
に埋め込もう」としている時点で、論理矛盾が起きていま
す。
SQL は、本来は API の位置づけですが、APIというには
柔軟過ぎます。
SQLをストアドプロシージャに隠蔽し、オブジェクト指向
言語と疎結合にするべきです。
39
Copyright 2016-2018 G1Systems Inc.
RDBMS も APIファーストで
テーブル設計はコーディングのあとで
40
Copyright 2016-2018 G1Systems Inc.
デスマーチの原因は「要件定義の甘さ」と言われるが……
ウォータフォール開発で
は、要件定義が甘いと、
手戻りが起きる。
特に、テーブル設計の変
更は、波及範囲が大きい。
これがデススパイラルの
元になる。
41
Copyright 2016-2018 G1Systems Inc.
デスマーチになる本当の原因
テーブル設計に変更が入ること!
例えば、某金融機関の開発では……
DDL変更依頼-毎週水曜日15時締切
DBAチームで精査検討会議 - 毎週木曜日
開発サーバへDDLの適用-毎週金曜日
開発メンバで設計書・コードへ反映
さらなる矛盾が顕在化!
デスマーチが鳴り響く!!
42
Copyright 2016-2018 G1Systems Inc.
デスマーチの原因は、要件定義とテーブル設計
43
エクセル方眼紙で
要件定義
顧客が最終形を
イメージできない
手戻りが発生する!
先にプログラムを
見せられれば良い!
あいまいな要件定義
を元にテーブル設計
手戻りの度に
修正が発生
多数のプログラムに
波及しデスマーチへ
コーディングの後に
テーブル設計を!
要件定義
テーブル設計
解決策
Copyright 2016-2018 G1Systems Inc.
インタフェースから先にアジャイル開発を進めよう
AP
RDBMS
インタフェース
仕様書
(Excel)
こんなふうに
使いたいんだけど
スタブ
自動生成
AP
アジャイル開発
(要件を固める/
UIを作るフェーズ)
RDBMS
AP table table
テーブル構造の
確定は要件が
固まってからでいい
アジャイル開発
(SQL開発フェーズ)
44
Copyright 2016-2018 G1Systems Inc.
RDBMSのAPIに必要な要素は4つ
1.プロシージャ名(ファンクション名)
2.引数と型
3.戻り値と型
4.ダミーデータ
45
Copyright 2016-2018 G1Systems Inc.
エクセルで設定する(プロシージャ名と引数)
46
Copyright 2016-2018 G1Systems Inc.
エクセルで設定する(戻り値)
47
Copyright 2016-2018 G1Systems Inc.
エクセルで設定する(ダミーデータ)
48
Copyright 2016-2018 G1Systems Inc.
マクロでソースを自動生成する(ダミービュー)
CREATE VIEW xpr_find_customer_VIEW AS
SELECT
CAST(NULL AS SIGNED) AS ID
, CAST(NULL AS CHAR) AS NAME ……
UNION ALL SELECT 1000, '山田 太郎'……
UNION ALL SELECT 1001, '佐藤 二郎'……
UNION ALL SELECT 1002, '鈴木 一郎'……
49
Copyright 2016-2018 G1Systems Inc.
マクロでソースを自動生成する(ストアドプロシージャ)
CREATE PROCEDURE pr_find_customer(IN _Name TEXT -- 名前で検索
, IN _Address TEXT -- 住所で検索)
BEGIN
-- 本番時は以下のSQLを修正し、このコメントを削除する。
SELECT
ID AS ID
, NAME AS NAME ……
FROM xpr_find_customer_VIEW
WHERE
ID IS NOT NULL
-- AND (NAME LIKE _Name OR _Name IS NULL)
-- AND (ADDRESS LIKE _Address OR _Address IS NULL);
End
$$
DELIMITER ;
50
Copyright 2016-2018 G1Systems Inc.
テーブルなしでUIの開発ができる
51
アプリケーションに入るSQLはこれだけになる。
アプリケーションから SQL を完全に排除できる!
Copyright 2016-2018 G1Systems Inc.
ストアドプロシージャは開発効率が悪いのでは?
年商50億円の企業の基幹システム
約120機能を、この手法で開発。
※ 見積、受発注、請求、入金、入出庫、製造、棚卸
スクラッチ開発で3ヵ月10人月!
作ったストアドプロシージャは440本
内フェッチしたもの(手続型処理)は4本だけ
52
Copyright 2016-2018 G1Systems Inc.
実演します!
53
Copyright 2016-2018 G1Systems Inc.
ご相談ください
SQL・RDBについてのコンサルティング、教育、
パフォーマンスチューニングなどお困りのことが
ございましたら、お気軽にご相談ください。
s.ikushima@g1sys.co.jp
54

More Related Content

Similar to Sql learning2

Alteryxの空間分析で学ぶ、最寄りの指定緊急避難場所と低水位地帯 Developers.IO Tokyo 2019
Alteryxの空間分析で学ぶ、最寄りの指定緊急避難場所と低水位地帯 Developers.IO Tokyo 2019Alteryxの空間分析で学ぶ、最寄りの指定緊急避難場所と低水位地帯 Developers.IO Tokyo 2019
Alteryxの空間分析で学ぶ、最寄りの指定緊急避難場所と低水位地帯 Developers.IO Tokyo 2019
Yuji Kanemoto
 
20090606 わんくま(がる)
20090606 わんくま(がる)20090606 わんくま(がる)
20090606 わんくま(がる)
galluda
 
LastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめようLastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめよう
Shinsuke Sugaya
 
20170428_【事前課題あり】ORACLE MASTER Bronze Oracle Database 12c 「12c SQL基礎[12c SQL]...
20170428_【事前課題あり】ORACLE MASTER Bronze Oracle Database 12c 「12c SQL基礎[12c SQL]...20170428_【事前課題あり】ORACLE MASTER Bronze Oracle Database 12c 「12c SQL基礎[12c SQL]...
20170428_【事前課題あり】ORACLE MASTER Bronze Oracle Database 12c 「12c SQL基礎[12c SQL]...
オラクルユニバーシティ
 
XP寺子屋第9回「シンプル・プログラミング」
XP寺子屋第9回「シンプル・プログラミング」XP寺子屋第9回「シンプル・プログラミング」
XP寺子屋第9回「シンプル・プログラミング」takepu
 
Amazon Elasticsearch Service & Open Distro for Elasticsearch Meetup
Amazon Elasticsearch Service & Open Distro for Elasticsearch MeetupAmazon Elasticsearch Service & Open Distro for Elasticsearch Meetup
Amazon Elasticsearch Service & Open Distro for Elasticsearch Meetup
Hibino Hisashi
 
Rails A/B testing by split gem
Rails A/B testing by split gemRails A/B testing by split gem
Rails A/B testing by split gem
Ryuma Tsukano
 
Head toward Java 15 and Java 16
Head toward Java 15 and Java 16Head toward Java 15 and Java 16
Head toward Java 15 and Java 16
Yuji Kubota
 
データサイエンスワールドからC++を眺めてみる
データサイエンスワールドからC++を眺めてみるデータサイエンスワールドからC++を眺めてみる
データサイエンスワールドからC++を眺めてみるShintaro Fukushima
 
今日こそわかる、安全なWebアプリの作り方2010
今日こそわかる、安全なWebアプリの作り方2010今日こそわかる、安全なWebアプリの作り方2010
今日こそわかる、安全なWebアプリの作り方2010
Hiroshi Tokumaru
 
Oracle APEX もくもく会 プラグインを作ろう
Oracle APEX もくもく会 プラグインを作ろうOracle APEX もくもく会 プラグインを作ろう
Oracle APEX もくもく会 プラグインを作ろう
良 亀井
 
[AWS EXpert Online for JAWS-UG 18] 見せてやるよ、Step Functions の本気ってやつをな
[AWS EXpert Online for JAWS-UG 18] 見せてやるよ、Step Functions の本気ってやつをな[AWS EXpert Online for JAWS-UG 18] 見せてやるよ、Step Functions の本気ってやつをな
[AWS EXpert Online for JAWS-UG 18] 見せてやるよ、Step Functions の本気ってやつをな
Amazon Web Services Japan
 
2019年度若手技術者向け講座 実践SQL
2019年度若手技術者向け講座 実践SQL2019年度若手技術者向け講座 実践SQL
2019年度若手技術者向け講座 実践SQL
keki3
 
パターン認識モデル初歩の初歩
パターン認識モデル初歩の初歩パターン認識モデル初歩の初歩
パターン認識モデル初歩の初歩
t_ichioka_sg
 
秀スクリプトの話
秀スクリプトの話秀スクリプトの話
秀スクリプトの話
Hiroshi Tokumaru
 
Lecture2
Lecture2Lecture2
Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理土岐 孝平
 
Sqlの書き方セミナー資料
Sqlの書き方セミナー資料Sqlの書き方セミナー資料
Sqlの書き方セミナー資料
Sadayoshi Ikushima
 
V$SQLとその周辺でER図を描いてみよう!
V$SQLとその周辺でER図を描いてみよう!V$SQLとその周辺でER図を描いてみよう!
V$SQLとその周辺でER図を描いてみよう!
歩 柴田
 
【修正版】Django + SQLAlchemy: シンプルWay
【修正版】Django + SQLAlchemy: シンプルWay【修正版】Django + SQLAlchemy: シンプルWay
【修正版】Django + SQLAlchemy: シンプルWay
Takayuki Shimizukawa
 

Similar to Sql learning2 (20)

Alteryxの空間分析で学ぶ、最寄りの指定緊急避難場所と低水位地帯 Developers.IO Tokyo 2019
Alteryxの空間分析で学ぶ、最寄りの指定緊急避難場所と低水位地帯 Developers.IO Tokyo 2019Alteryxの空間分析で学ぶ、最寄りの指定緊急避難場所と低水位地帯 Developers.IO Tokyo 2019
Alteryxの空間分析で学ぶ、最寄りの指定緊急避難場所と低水位地帯 Developers.IO Tokyo 2019
 
20090606 わんくま(がる)
20090606 わんくま(がる)20090606 わんくま(がる)
20090606 わんくま(がる)
 
LastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめようLastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめよう
 
20170428_【事前課題あり】ORACLE MASTER Bronze Oracle Database 12c 「12c SQL基礎[12c SQL]...
20170428_【事前課題あり】ORACLE MASTER Bronze Oracle Database 12c 「12c SQL基礎[12c SQL]...20170428_【事前課題あり】ORACLE MASTER Bronze Oracle Database 12c 「12c SQL基礎[12c SQL]...
20170428_【事前課題あり】ORACLE MASTER Bronze Oracle Database 12c 「12c SQL基礎[12c SQL]...
 
XP寺子屋第9回「シンプル・プログラミング」
XP寺子屋第9回「シンプル・プログラミング」XP寺子屋第9回「シンプル・プログラミング」
XP寺子屋第9回「シンプル・プログラミング」
 
Amazon Elasticsearch Service & Open Distro for Elasticsearch Meetup
Amazon Elasticsearch Service & Open Distro for Elasticsearch MeetupAmazon Elasticsearch Service & Open Distro for Elasticsearch Meetup
Amazon Elasticsearch Service & Open Distro for Elasticsearch Meetup
 
Rails A/B testing by split gem
Rails A/B testing by split gemRails A/B testing by split gem
Rails A/B testing by split gem
 
Head toward Java 15 and Java 16
Head toward Java 15 and Java 16Head toward Java 15 and Java 16
Head toward Java 15 and Java 16
 
データサイエンスワールドからC++を眺めてみる
データサイエンスワールドからC++を眺めてみるデータサイエンスワールドからC++を眺めてみる
データサイエンスワールドからC++を眺めてみる
 
今日こそわかる、安全なWebアプリの作り方2010
今日こそわかる、安全なWebアプリの作り方2010今日こそわかる、安全なWebアプリの作り方2010
今日こそわかる、安全なWebアプリの作り方2010
 
Oracle APEX もくもく会 プラグインを作ろう
Oracle APEX もくもく会 プラグインを作ろうOracle APEX もくもく会 プラグインを作ろう
Oracle APEX もくもく会 プラグインを作ろう
 
[AWS EXpert Online for JAWS-UG 18] 見せてやるよ、Step Functions の本気ってやつをな
[AWS EXpert Online for JAWS-UG 18] 見せてやるよ、Step Functions の本気ってやつをな[AWS EXpert Online for JAWS-UG 18] 見せてやるよ、Step Functions の本気ってやつをな
[AWS EXpert Online for JAWS-UG 18] 見せてやるよ、Step Functions の本気ってやつをな
 
2019年度若手技術者向け講座 実践SQL
2019年度若手技術者向け講座 実践SQL2019年度若手技術者向け講座 実践SQL
2019年度若手技術者向け講座 実践SQL
 
パターン認識モデル初歩の初歩
パターン認識モデル初歩の初歩パターン認識モデル初歩の初歩
パターン認識モデル初歩の初歩
 
秀スクリプトの話
秀スクリプトの話秀スクリプトの話
秀スクリプトの話
 
Lecture2
Lecture2Lecture2
Lecture2
 
Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理
 
Sqlの書き方セミナー資料
Sqlの書き方セミナー資料Sqlの書き方セミナー資料
Sqlの書き方セミナー資料
 
V$SQLとその周辺でER図を描いてみよう!
V$SQLとその周辺でER図を描いてみよう!V$SQLとその周辺でER図を描いてみよう!
V$SQLとその周辺でER図を描いてみよう!
 
【修正版】Django + SQLAlchemy: シンプルWay
【修正版】Django + SQLAlchemy: シンプルWay【修正版】Django + SQLAlchemy: シンプルWay
【修正版】Django + SQLAlchemy: シンプルWay
 

Sql learning2

  • 1. Copyright 2016-2018 G1Systems Inc. ストアドプロシージャを使っ た開発について 中級者向け 1
  • 2. Copyright 2016-2018 G1Systems Inc. はじめに SQLおじさんですw SQLServerだけではなく、RDB全般について 専門的に仕事を請けています。 金融から、製造業、ネットゲームまで、オー ルランドに対応しております。 その中で、今日はストアドプロシージャを 使った開発についてお話します。 2
  • 3. Copyright 2016-2018 G1Systems Inc. 前回の復習 3
  • 4. Copyright 2016-2018 G1Systems Inc.4 例題 すべての生徒のリストに、特待生マスタの削除フラグが 0の 特待生ランクを出力してください。 2 C 生徒ID ランク 3 A 10 B 33 C 40 B 48 C 1石野 扶樹 ID氏名 2岩崎 研二 3岩間 竜也 4上野 浩介 5岡崎 雅之 6岡島 慶二 生徒マスタ 特待生マスタ 1 削除フラグ 0 0 0 0 0
  • 5. Copyright 2016-2018 G1Systems Inc. 解答 5 SELECT a.氏名, b.ランク FROM 生徒マスタ a LEFT OUTER JOIN 特待生マスタ b ここに結合条件を追加 これを出力 したくない 生徒マスタ 特待生マスタ 2 C 生徒ID ランク 3 A 10 B 33 C 40 B 48 C 1石野 扶樹 ID氏名 2岩崎 研二 3岩間 竜也 4上野 浩介 5岡崎 雅之 6岡島 慶二 1 削除フラグ 0 0 0 0 0
  • 6. Copyright 2016-2018 G1Systems Inc. これはNG! 6 SELECT a.氏名, b.ランク FROM 生徒マスタ a LEFT OUTER JOIN 特待生マスタ b ON a.ID = b.生徒ID WHERE b.削除フラグ = 0;
  • 7. Copyright 2016-2018 G1Systems Inc. なぜNGか? 7 WHERE 削除FLAG = 0 では、 NULL = 0 となる、 のレコードが出力できない。 1行だけになってしまう。 ← NULL = 0 は False ← NULL = 0 は False ← NULL = 0 は False 生徒マスタ 特待生マスタ 2 C 生徒ID ランク 3 A (4) NULL (5) NULL (6) NULL 1石野 扶樹 ID氏名 2岩崎 研二 3岩間 竜也 4上野 浩介 5岡崎 雅之 6岡島 慶二 1 削除フラグ 0 NULL NULL NULL ← NULL = 0 は False 10 B 33 C 40 B 0 0 0 (1) NULL NULL ← 1= 0 は False
  • 8. Copyright 2016-2018 G1Systems Inc. サブクエリーは意味は正しいけれど…… 8 SELECT a.氏名, b.ランク FROM 生徒マスタ a LEFT OUTER JOIN (SELECT * FROM 特待生マスタ WHERE 削除フラグ = 0) b ON a.ID = b.生徒ID;
  • 9. Copyright 2016-2018 G1Systems Inc. 正しくはこうする! 9 SELECT a.氏名, b.ランク FROM 生徒マスタ a LEFT OUTER JOIN 特待生マスタ b ON a.ID = b.生徒ID AND 0 = b.削除フラグ;
  • 10. Copyright 2016-2018 G1Systems Inc. イメージにすると…… 10 生徒マスタ a 特待生マスタ b a.ID = b.生徒ID AND b.削除フラグ = 0 a.ID = b.生徒ID AND b.削除フラグ <> 0 a.ID <> b.生徒ID AND b.削除フラグ = 0 a.ID <> b.生徒ID AND b.削除フラグ <> 0 b.削除フラグ = 0 で 全体を削りたい訳ではない。
  • 11. Copyright 2016-2018 G1Systems Inc. SQLServer や Oracle などはサブクエリを直す SQLServer や Oracle などの商用DBは、 11 SELECT a.氏名, b.ランク FROM 生徒マスタ a LEFT OUTER JOIN (SELECT * FROM 特待生マスタ WHERE 削除フラグ = 0) b ON a.ID = b.生徒ID; SELECT a.氏名, b.ランク FROM 生徒マスタ a LEFT OUTER JOIN 特待生マスタ b ON a.ID = b.生徒ID AND 0 = b.削除フラグ; パースの段階で SQL を直してから実行します。 直してくれない RDBMS は めっちゃ遅い! 特にハッシュジョインがない MySQL は OUT!
  • 12. Copyright 2016-2018 G1Systems Inc. 右に置いたテーブルがWHERE句に入るとバグ 12 SELECT a.氏名, b.ランク FROM 生徒マスタ a LEFT OUTER JOIN 特待生マスタ b ON a.ID = b.生徒ID WHERE b.ランク = 'A'; 外部結合を打消してしまう。 どちらを意図しているのか、 ソースからは分からない。
  • 13. Copyright 2016-2018 G1Systems Inc. ところが、例えば、WordPress 4.9.4 での例 if ( $post_status_join ) { $join .= " LEFT JOIN {$wpdb->posts} AS p2 ON ({$wpdb->posts}.post_parent = p2.ID)"; foreach ( $statuswheres as $index => $statuswhere ) { $statuswheres[$index] = "($statuswhere OR ({$wpdb->posts}.post_status = 'inherit’ AND ".str_replace( $wpdb->posts, 'p2', $statuswhere ) . "))"; } } $where_status = implode( ' OR ', $statuswheres ); if ( ! empty( $where_status ) ) { $where .= " AND ($where_status)"; } ※ class-wp-query.php 13
  • 14. Copyright 2016-2018 G1Systems Inc. WordPress 4.9.4 は、最後に LEFT JOIN に変換 /** Generates SQL clauses to be appended to a main query. -- 中略 -- public function get_sql( $type, $primary_table, …… -- 中略 -- /* If any JOINs are LEFT JOINs (as in the case of NOT EXISTS), then all JOINs should be LEFT. Otherwise posts with no metadata will be excluded from results. */ -- 中略 -- if ( false !== strpos( $sql['join'], 'LEFT JOIN' ) ) { $sql['join'] = str_replace( 'INNER JOIN', 'LEFT JOIN', $sql['join'] ); } -- 中略 -- ※ class-wp-meta-query.php 14
  • 15. Copyright 2016-2018 G1Systems Inc. 一応、Word Press がやっている変換意図を解説 15 生徒マスタ 特待生マスタ 2 C 生徒ID ランク 3 A (4) NULL (5) NULL (6) NULL 1石野 扶樹 ID氏名 2岩崎 研二 3岩間 竜也 4上野 浩介 5岡崎 雅之 6岡島 慶二 1 削除フラグ 0 NULL NULL NULL 10 B 33 C 40 B 0 0 0 (1) NULLNULL ランク名称マスタ 学業特待生AA 名称ランク 学業特待生BB スポーツ特待生C こちらINNER JOIN にすると、 B・Cに一致するものがない ため、外部結合を打消してし まう。こちらを LEFT JOIN
  • 16. Copyright 2016-2018 G1Systems Inc. ここまでのまとめ 何年か前、「すべての変数を Static で宣言したらしっく りくる」とブログに書いて炎上した人がいました。 しかし、すべての JOIN を LEFT でというのは、まったく 珍しくありません。新人にそう教育している大手企業をい くつも知っています。 どちらも間違っていますが、どちらが実害が大きいかは明 らかです。 LEFT 決め打ちは、「すべての変数を Static で宣言」よ り技術レベルが低い。と心得ましょう。 16
  • 17. Copyright 2016-2018 G1Systems Inc. WHERE句は論理演算の塊 17
  • 18. Copyright 2016-2018 G1Systems Inc. 論理演算を復習しよう! AND(論理積)は掛け算、OR(論理和)は足し算 True は 1(0以外) False は 0 として、簡単な数式に直して考えてみましょう。 もちろん、演算の順序も掛け算(AND)が先です。 T and T and F and T and T and T = 1 × 1 × 0 × 1 × 1 × 1 = 0 (False) F or F or F or T or F or F = 0 + 0 + 0 + 1 + 0 + 0 = 1 (True) 18
  • 19. Copyright 2016-2018 G1Systems Inc. 因数分解、展開も数式と同じ (a × b) + (a × c) = a × (b + c) (a AND b) OR (a AND c) 男性で日本人、または、男性でアメリカ人 = a AND (b OR c) 男性で、日本人、または、アメリカ人 これらは、SQLに限らずどんな言語でも必要なので、息をす るのと同じレベルでできるようになってください。 19
  • 20. Copyright 2016-2018 G1Systems Inc. SQLの動的生成を避ける! ただし、Oracleではできません! 20
  • 21. Copyright 2016-2018 G1Systems Inc. SQLの動的生成を避ける1 21 keyの範囲を指定してレコードを検索する処理を考える 画面 開始値 終了値 1 10 WHERE句 開始値・終了値の有無に応じて 4種類のWHERE句が必要になる 開始値 終了値 なしなし なし ID >= 開始値あり なし ID <= 終了値なし あり ID >= 開始値 AND ID <= 終了値あり あり
  • 22. Copyright 2016-2018 G1Systems Inc. sqlWhere = ""; if( 開始値 != null){ sqlWhere = "WHERE "; sqlWhere += " col1 >= " + 開始値; } if( 終了値 != null){ if(sqlWhere == ""){ sqlWhere += " WHERE "; } else { sqlWhere += " AND "; } sqlWhere += " col1 <= " + 終了値; } if(sqlWhere != ""){ sql += sqlWhere; } 22 古典的なSQL文生成ロジックを書くと……
  • 23. Copyright 2016-2018 G1Systems Inc. sqlWhere = " WHERE 1 = 1 "; if( 開始値 != null){ sqlWhere += " AND col1 >= @開始値"; // パラメータ(param)を生成して Paramaters.Add(param); } if( 終了値 != null){ sqlWhere += " AND col1 <= @終了値"; // パラメータ(param)を生成して Paramaters.Add(param); } sql += sqlWhere; 23 SQL文生成ロジックを書くと……
  • 24. Copyright 2016-2018 G1Systems Inc. 実は、動的生成は不要です。 SELECT * FROM table_a WHERE (col1 >= @開始値 OR @開始値 IS NULL) AND (col1 <= @終了値 OR @終了値 IS NULL); 24 ※ 当然、FROM句、HAVING句でも使えます!
  • 25. Copyright 2016-2018 G1Systems Inc. パースされると消える! 25 (col1 >= @開始値 OR @開始値 IS NULL) @開始値がNULL @開始値が1000 (col1 >= NULL OR NULL IS NULL) (col1 >= 1000 OR 1000 IS NULL) (col1 >= NULL OR True) (col1 >= 1000 OR False) 意味がないので消える (col1 >= 1000)だけが残る
  • 26. Copyright 2016-2018 G1Systems Inc. SQLServerは、RECOMPILE指定する SELECT * FROM テーブル WHERE (col1 = @検索値1 OR @検索値1 IS NULL) AND (col2 = @検索値2 OR @検索値2 IS NULL) OPTION(RECOMPILE); とすれば、毎回、パースからやり直してくれる。 26
  • 27. Copyright 2016-2018 G1Systems Inc. 更には……(任意の OR条件を追加) 27 画面 開始値 終了値 1 10 または 区分 A SELECT * FROM table_a WHERE ((col1 >= @開始値 OR @開始値 IS NULL) AND (col1 <= @終了値 OR @終了値 IS NULL)) OR (col2 = @区分 AND @区分 IS NOT NULL) ※ 当然、FROM句、HAVING句でも使えます!
  • 28. Copyright 2016-2018 G1Systems Inc. 更には…… 28 画面 検索値 比較演算子 1 <= SELECT * FROM table_a WHERE (col1 = 検索値 OR @比較演算子 <> "=") AND (col1 >= 検索値 OR @比較演算子 <> ">=") AND (col1 <= 検索値 OR @比較演算子 <> "<=") AND (col1 > 検索値 OR @比較演算子 <> ">") AND (col1 < 検索値 OR @比較演算子 <> "<") ※ 当然、FROM句、HAVING句でも使えます! ▼
  • 29. Copyright 2016-2018 G1Systems Inc. LEFT JOIN を切り替えるなら 29 画面 過去特待生だった らそれも表示 @区分 が 1 なら削除フラグが立っていても出力し、 以外ならしない。 SELECT a.氏名, b.ランク FROM 生徒マスタ a LEFT OUTER JOIN 特待生マスタ b ON a.ID = b.生徒ID AND (0 = b.削除フラグ OR @区分 = 1); する しない
  • 30. Copyright 2016-2018 G1Systems Inc. まとめ – SQLの動的生成は要らない 弊社で開発した ERP のスクラッチ案件 見積、受注、発注、売上、請求、入金、部品表、在庫引当、 入庫、出荷、棚卸、作業費、外注管理、交通費、利益管理 全て、ストアドプロシージャで作成。 SQLの動的生成はゼロ! 30
  • 31. Copyright 2016-2018 G1Systems Inc. 実演します SQLのイメージの仕方 31
  • 32. Copyright 2016-2018 G1Systems Inc. MVCは間違っている 32
  • 33. Copyright 2016-2018 G1Systems Inc. ヒットするデータが少ないと予想したとき 33 インデックスを抽出して プライマリーキー(実データ) をループしながら結果セットを 作っていきます。
  • 34. Copyright 2016-2018 G1Systems Inc. ヒットするデータが少ないと予想したとき RowIDLists[] rowIDs New RowIDLists[] ; // ヒットしたもの RetrunRows[] retRows New RetrunRows[] ; // 戻すレコード rowIDs = IX_売上日.getRange(#日付F#, #日付T#); //日付範囲 for(RowID rowID:rowIDs){ // 計算処理 retRows.add(売上.getRow(rowID)); } Return retRows; 34
  • 35. Copyright 2016-2018 G1Systems Inc. MVCは1980年代のスタンドアローン向け概念 35 スタンドアローンPC View Control Model
  • 36. Copyright 2016-2018 G1Systems Inc. DBサーバ Webに適用するとインピーダンスミスマッチ 36 WEBサーバ APサーバ View Control Model SQL SQLは界面が 合わない異物
  • 37. Copyright 2016-2018 G1Systems Inc. O/Rマッパで解消 DBサーバWEBサーバ APサーバ View Control Model SQL O/Rマッパで 異物を覆う
  • 38. Copyright 2016-2018 G1Systems Inc. 本来はDBを疎結合にすべき(異物は隠蔽すべき) 38 DBサーバWEB サーバ APサーバ View Control Model RDBMS DBサーバ RDBMS Inter face Inter face
  • 39. Copyright 2016-2018 G1Systems Inc. MVCは1980年代に生まれた概念 MVCは1980年代に生まれた概念で、Webも、DBも意識 して作られていません。 「疎結合にすべき」という概念なのに、メモリー空間も、 処理構造も全く違う RDBMS を「オブジェクト指向言語 に埋め込もう」としている時点で、論理矛盾が起きていま す。 SQL は、本来は API の位置づけですが、APIというには 柔軟過ぎます。 SQLをストアドプロシージャに隠蔽し、オブジェクト指向 言語と疎結合にするべきです。 39
  • 40. Copyright 2016-2018 G1Systems Inc. RDBMS も APIファーストで テーブル設計はコーディングのあとで 40
  • 41. Copyright 2016-2018 G1Systems Inc. デスマーチの原因は「要件定義の甘さ」と言われるが…… ウォータフォール開発で は、要件定義が甘いと、 手戻りが起きる。 特に、テーブル設計の変 更は、波及範囲が大きい。 これがデススパイラルの 元になる。 41
  • 42. Copyright 2016-2018 G1Systems Inc. デスマーチになる本当の原因 テーブル設計に変更が入ること! 例えば、某金融機関の開発では…… DDL変更依頼-毎週水曜日15時締切 DBAチームで精査検討会議 - 毎週木曜日 開発サーバへDDLの適用-毎週金曜日 開発メンバで設計書・コードへ反映 さらなる矛盾が顕在化! デスマーチが鳴り響く!! 42
  • 43. Copyright 2016-2018 G1Systems Inc. デスマーチの原因は、要件定義とテーブル設計 43 エクセル方眼紙で 要件定義 顧客が最終形を イメージできない 手戻りが発生する! 先にプログラムを 見せられれば良い! あいまいな要件定義 を元にテーブル設計 手戻りの度に 修正が発生 多数のプログラムに 波及しデスマーチへ コーディングの後に テーブル設計を! 要件定義 テーブル設計 解決策
  • 44. Copyright 2016-2018 G1Systems Inc. インタフェースから先にアジャイル開発を進めよう AP RDBMS インタフェース 仕様書 (Excel) こんなふうに 使いたいんだけど スタブ 自動生成 AP アジャイル開発 (要件を固める/ UIを作るフェーズ) RDBMS AP table table テーブル構造の 確定は要件が 固まってからでいい アジャイル開発 (SQL開発フェーズ) 44
  • 45. Copyright 2016-2018 G1Systems Inc. RDBMSのAPIに必要な要素は4つ 1.プロシージャ名(ファンクション名) 2.引数と型 3.戻り値と型 4.ダミーデータ 45
  • 46. Copyright 2016-2018 G1Systems Inc. エクセルで設定する(プロシージャ名と引数) 46
  • 47. Copyright 2016-2018 G1Systems Inc. エクセルで設定する(戻り値) 47
  • 48. Copyright 2016-2018 G1Systems Inc. エクセルで設定する(ダミーデータ) 48
  • 49. Copyright 2016-2018 G1Systems Inc. マクロでソースを自動生成する(ダミービュー) CREATE VIEW xpr_find_customer_VIEW AS SELECT CAST(NULL AS SIGNED) AS ID , CAST(NULL AS CHAR) AS NAME …… UNION ALL SELECT 1000, '山田 太郎'…… UNION ALL SELECT 1001, '佐藤 二郎'…… UNION ALL SELECT 1002, '鈴木 一郎'…… 49
  • 50. Copyright 2016-2018 G1Systems Inc. マクロでソースを自動生成する(ストアドプロシージャ) CREATE PROCEDURE pr_find_customer(IN _Name TEXT -- 名前で検索 , IN _Address TEXT -- 住所で検索) BEGIN -- 本番時は以下のSQLを修正し、このコメントを削除する。 SELECT ID AS ID , NAME AS NAME …… FROM xpr_find_customer_VIEW WHERE ID IS NOT NULL -- AND (NAME LIKE _Name OR _Name IS NULL) -- AND (ADDRESS LIKE _Address OR _Address IS NULL); End $$ DELIMITER ; 50
  • 51. Copyright 2016-2018 G1Systems Inc. テーブルなしでUIの開発ができる 51 アプリケーションに入るSQLはこれだけになる。 アプリケーションから SQL を完全に排除できる!
  • 52. Copyright 2016-2018 G1Systems Inc. ストアドプロシージャは開発効率が悪いのでは? 年商50億円の企業の基幹システム 約120機能を、この手法で開発。 ※ 見積、受発注、請求、入金、入出庫、製造、棚卸 スクラッチ開発で3ヵ月10人月! 作ったストアドプロシージャは440本 内フェッチしたもの(手続型処理)は4本だけ 52
  • 53. Copyright 2016-2018 G1Systems Inc. 実演します! 53
  • 54. Copyright 2016-2018 G1Systems Inc. ご相談ください SQL・RDBについてのコンサルティング、教育、 パフォーマンスチューニングなどお困りのことが ございましたら、お気軽にご相談ください。 s.ikushima@g1sys.co.jp 54