昨日のわんくまで言わなかったこと、発表資料だけではわからないことです。
ちなみに発表資料はこちら→わんくま 名古屋勉強会 #11 の発表用資料 - 予定は未定Blog版
昨日のわんくまの昼休みに TDD 道場があったんですが、テストコードのリファクタリングについて賛否あったのでちょっと自分の考えをまとめておきます。
それに加え、C# と NUnit でどのようにテストコードをリファクタリングできるか、というのも紹介します。
というかこちらがメイン。
テストを追加した際に追加したテストだけを実行するか全部実行するかというのも意見が分かれたんですが、主に個別に指定するのが面倒という理由で全部実行する派です。
全部実行すると時間がかかる?それはもはや単体テストじゃないですね。重いテストは分割して分離しちゃいましょう。
これに関してはレガシーコード改善ガイド (Object Oriented SELECTION)をどうぞ。機会があればここら辺についても書きたいところです。
Git でどういうことができるのかの紹介です。
まだ Git を使ったことが無い人・使いはじめの人を対象としています。たぶん。
こちらもあわせてどうぞ:言わなかったこと・発表資料だけではわからないこと - 予定は未定Blog版
なんか流行ってるらしいので。
他の言語をある程度知っている人はこれを読めば SQL (再帰 CTE) の基礎をマスターして SQL (再帰 CTE) を書くことができるようになります。
・・・嘘ですごめんなさい。
いつもの通り、SQL Server 2005/2008 でしか試してないよ!
コメントは 2 とおり
-- 一行コメント /* 複数行 コメント */
-- 1から10までの数字を表示するSQL WITH -- 入力は1から10まで Input(f, t) AS ( SELECT 1, 10 ) , Seq(n) AS ( -- 最初はInputのf SELECT f FROM Input UNION ALL -- それ以降は1ずつ数値をインクリメント SELECT n + 1 FROM Seq WHERE -- n + 1がInputのtより小さい間出力 n + 1 <= (SELECT t FROM Input) ) -- 出力 SELECT n FROM Seq ORDER BY n ;
このように、WITH Input・・・処理 (UNION ALL を使用した共通表式)・・・出力 (最終的な SELECT) の形をとります。
また、いろいろと変形が考えられ、たとえば
WITH Input(f, t) AS ( SELECT 1, 10 ) , Seq(n) AS ( SELECT f FROM Input UNION ALL SELECT n + 1 FROM Seq INNER JOIN Input ON Seq.n + 1 <= Input.t ) SELECT n FROM Seq ORDER BY n ;
とも記述できます。
変数は以下のように定義します。
変数のグループ名(変数名1, 変数名2, ...) AS ( SELECT 変数名1の値, 変数名2の値 ... )
Input も変数ということになります。
また、変数は定義した場所以降でどこでも使えますが、値を変更することはできません。
整数も実数も使えます。
SELECT 10, 0.5
SELECT 1 + 1 SELECT 1 - 1 SELECT 1 * 2 SELECT 5 / 2 SELECT 5.0 / 2 SELECT 5 % 2
ありません。
文字列はシングルクォートで囲みます。
プレフィックスとして N を付けると Unicode 定数になります。
SELECT 'abc' SELECT N'abc'
-- 結合 SELECT 'aaa' + 'bbb' -- aaabbb -- 分割・・・後で -- 長さ SELECT LEN('abcdef') -- 6 -- 切り出し SELECT SUBSTRING('abcd', 1, 3) -- abc -- 検索 SELECT CHARINDEX('bc', 'abcd') -- 2
分割を行う関数は無いし何返せばいいのか分からないので CTE で代用します。
WITH Input(s, delim) AS ( SELECT 'aaa,bbb,ccc', ',' ) , SplitCore(i, res, delim, s) AS ( SELECT 0, CAST(NULL AS varchar(max)), delim, s FROM Input UNION ALL SELECT i + 1 , CAST(COALESCE(LEFT(s, NULLIF(CHARINDEX(delim, s), 0) - 1), s) AS varchar(max)) , delim , SUBSTRING(s, NULLIF(CHARINDEX(delim, s), 0) + 1, LEN(s)) FROM SplitCore WHERE s IS NOT NULL ) , Split(i, res) AS ( SELECT i, res FROM SplitCore WHERE res IS NOT NULL ) SELECT res FROM Split ORDER BY i
配列を使いたくなったら SELECT で代用しましょう。
WITH Array(i, val) AS ( SELECT 0, 100 UNION ALL SELECT 1, 200 UNION ALL SELECT 2, 300 ) SELECT i, val FROM Array UNION ALL -- 要素の個数 SELECT COUNT(*), NULL FROM Array
-- ここらへん一体何に使うんでしょうね?わかりません WITH Array(i, val) AS ( SELECT 0, 1 UNION ALL SELECT 1, 2 UNION ALL SELECT 2, 3 ) -- 先頭を取り出す SELECT TOP 1 * FROM Array UNION ALL -- 末尾を取り出す SELECT i, val FROM Array WHERE i = (SELECT MAX(i) FROM Array) UNION ALL -- 末尾に追加 SELECT i, val FROM Array UNION ALL SELECT MAX(i) + 1, 9 FROM Array
文は全体で一文なので、制御文はないです。
分岐には CASE 式を使用します。
-- 単純CASE式 CASE col WHEN 'a' THEN 0 WHEN 'b' THEN 10 ELSE -1 END --検索CASE式 CASE WHEN col = 'a' THEN 0 WHEN col IN('b', 'c') THEN 10 ELSE -1 END
繰り返しには再帰 CTE を使います。
パターンとしてはいくつもありますが、文字列の分割で示した入力をループごとに減らしていく方法の他に、添え字を使用することもできます。
WITH -- 入力に添え字を追加する Input(i, s) AS ( SELECT 0, 'aaa' UNION ALL SELECT 1, 'bbb' UNION ALL SELECT 2, 'ccc' ) , MaxIdx(i) AS ( SELECT MAX(i) FROM Input ) , StrJoin(s, i) AS ( SELECT CAST(s AS varchar(max)) , i FROM Input WHERE i = 0 UNION ALL SELECT CAST(S.s + I.s AS varchar(max)) -- 添え字を増やしていく(場合によっては減らしていく) , S.i + 1 FROM StrJoin S INNER JOIN Input I ON S.i + 1 = I.i WHERE -- 添え字で終了を判断 S.i <> (SELECT i FROM MaxIdx) ) , Result(s) AS ( SELECT s FROM StrJoin WHERE i = (SELECT i FROM MaxIdx) ) SELECT * FROM Result
ありません。
できません。
って何かありますかね?
え?再帰 CTE なんて使わない?ハハハ、そんなバカな。
追記:
ありました!ありましたよ知っておいた方がいい○○!
再帰の上限を設定し、それ以上再帰されるとエラーになります。
WITH Seq(n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM Seq WHERE n < 150 ) SELECT * FROM Seq OPTION (MAXRECURSION 200)
最後の OPTION (MAXRECURSION 200) というのがそれです。
何も指定しないと 100 を指定したときと変わらないので、OPTION 部分をはずすと実行時にエラーになります。
また、0 を指定すると無制限になります。最強ですね。
再帰の上限がなくなった SQL にもはや敵など存在しないも同然です。
ほかにも、BrainCrash なんてものももちろん実装できます。
でも一番最強だと思ったのは、電卓ですかね。
昨日のエントリの「演算子に対応する名前」で + や - に対応する名前は Add や Subtract よりも Plus や Minus の方がいいと書いたけど、Scala ではどうなってるのか試してみた。
scala> def +-(){}
$plus$minus: ()Unit
おぉ、plus と minus になってますね!
・・・まぁ Scala は operator + の多重定義というか、そもそもメソッド名に + とか普通に使えて、ただ単に記号としてマッピングしてるから add じゃなくて plus ってつけてる、と言えなくもないけど。
なんで、
scala> def !(){}
$bang: ()Unit
だしね。
.NETのクラスライブラリ設計 開発チーム直伝の設計原則、コーディング標準、パターン (Microsoft.net Development Series)
とっくに読み終わっていたんだけど、まとめる時間がなかったのでかなり時間が空いてしまった・・・
ということで基本的には「・・・ん?」って思ったところとかのまとめです。
msysgit で日本語ファイル名を含むリポジトリの clone を作ると、文字化けしちゃうことがあります。
とりあえず試したのは、
| clone 元 | 結果 |
|---|---|
| 別 PC の Cygwin 版 Git | 文字化け |
| 同一 PC の msysgit | 文字化けしない |
と、こんな感じです。
他のパターンを試した方は是非教えてください。
で、このままではイヤなので、日本語ファイル名が扱えるように msysgit に手を入れてみました*1。
ただ、まだ途中なので、もっと良い方法がある!とか、完全版にしてやんよ!って人がいたら是非!
*1:Bazaar 使え?いや、Git が使いたいんです!