SQLのエリアス名、頭文字省略は...うーん

SQL特有の問題である「世の中で統一された習慣がない」という、まさしくその部分の話なので、「こうすべし」ってのは言えないのですが...

少なくともちょっと思ったこと、そして、jflute流の書き方をちょいっと紹介。

※ここでいうエリアス名(alias名)はテーブルのです。

よくあるエリアス名

こんなのをよく見かけます。

select ...
  from MEMBER m
    left outer join MEMBER_STATUS ms on ...
    left outer join MEMBER_SERVICE msv on ...
    left outer join MEMBER_SECURITY msc on ...
 where ...

MEMBERの先頭文字: m

MEMBER_STATUSの先頭文字: m + s

MEMBER_SERVICEの先頭文字でかぶっちゃったから
 なにかしらもう一文字: m + s + v

MEMBER_SECURITYの先頭文字もかぶっちゃったから
 なにかしらもう一文字: m + s + c

jfluteはふと思うのです...

もう ms 要らなくない?

「STATUSの方が何もなくなってしまうじゃん!」
ってそういうことじゃなくって...

MEMBER_というprefixによる識別に意味が無くない?

っていうこと。

だってもう MEMBER 兄弟、いや姉妹!? ばっかりじゃん。サンプルのSQLはselect句とwhere句を省略してますが、そこにちゃんと入ってくると結構ややこしいですよ。

ですが、実際に技術者の方にSQLを書いてもらうと、こうなることがわりと多いのです。

壮大なるバグ

単に気分的な話ならわざわざブログ書いたりしませんが、
これが壮大なるバグを引き起こす可能性があります。

select ...
  from FOO_BAR_ORDER fbo
    left outer join FOO_BAR_ADDITIONAL fba
      on fbo.FIRST_PK = fba.FIRST_PK
     and fbo.SECOND_PK = fba.SECOND_PK
     and fbo.THIRD_PK = fba.THIRD_PK
    left outer join FOO_BAR_SALE fbs
      on fbo.FIRST_FK = fbs.FIRST_PK
     and fbo.SECOND_FK = fbs.SECOND_PK
     and fbo.THIRD_FK = fba.THIRD_PK
     and fbo.FOURTH_FK = fbs.FOURTH_PK
-- where is the mistake?

さあ、どこが間違いでしょう?こちら新卒研修で新卒たちに探してもらいました。すぐに見つける人もいれば、ずーーっと見つからない人もいました。

まあ、SQLが落ちれば安全ではありますけどね、万が一落ちなかったらちょーつらい。上記のSQL複合主キーのつらさを語る例 なので、ちょっと極端な感じではありますけど、業務のSQLはもっと複雑、「たまたまエラーにならずに通っちゃう」みたいなことは、ありえなくないかなーと。

エリアス名でバグ防止

で、これ、エリアス名がもうちょいどうにかなっていれば発生しないバグかなーって。例えば...

select ...
  from FOO_BAR_ORDER odr
    left outer join FOO_BAR_ADDITIONAL addi
      on odr.FIRST_PK = addi.FIRST_PK
     and odr.SECOND_PK = addi.SECOND_PK
     and odr.THIRD_PK = addi.THIRD_PK
    left outer join FOO_BAR_SALE sale
      on odr.FIRST_FK = sale.FIRST_PK
     and odr.SECOND_FK = sale.SECOND_PK
     and odr.THIRD_FK = addi.THIRD_PK
     and odr.FOURTH_FK = sale.FOURTH_PK
-- where is the mistake?

なら、すぐに間違い気付きますよね。たぶん、書きながら間違いに気付くだろうから、そもそもこんな状態になりにくいかと。

そう、FOO_BARはみんな同じなんだから、その部分を使っても識別子にならない。このSQLの世界では、ORDER や ADDITIONAL や SALE などが、テーブルを識別する一番のキーワードなので、それらに着目したエリアス名を付けるといいかも。

さっきのSQLもその識別が含まれてはいますが、fbo,fba,fbsと一文字だけでとっても見づらい。

似た者同士で集まる

これって、どういうことか?

そう...

結合するテーブルに限って名前が似てるんですよ

そういうものですよね。そういうテーブル名の設計が多いかと。そして、それはとても自然なことかと。

MEMBER, MEMBER_STATUS, MEMBER_SERVICE,
MEMBER_SECURITY, MEMBER_WITHDRAWAL など。

もちろん、違う STATUS や違う SERVICE がいたら、そうもいかないですが、そのケースは多い方ではないかと。それはそのときに識別するprefixを付ければいいかなと。mbStat とか mbServ とか。。。

ただ...

少なくとも、一文字だけの違いにはしないこと

とにかく、似た者同士で集まりやすいんだから、よく使われる「頭文字省略方式」は、SQLのエリアス名に向いてないんじゃないか?って切に思うのです。

「頭文字省略方式」のメリットは、何も考えずに規則的にできること。そういうのプログラマーは好きですよね。感覚的な命名作業をするより、規則があってその通りにやる方が楽だと。それはよくわかるので、Javaの世界だと使ったりしますが、SQLの世界では少なくともjfluteは使わないようにしています。

jfluteが書いてみると...

先ほどのMEMBERテーブルの例で試してみると、

select ...
  from MEMBER mb
    left outer join MEMBER_STATUS stat on ...
    left outer join MEMBER_SERVICE serv on ...
    left outer join MEMBER_SECURITY sec on ...
 where ...

こんな感じですかね。

そのポリシーは...

一文字のエリアス名は使わない

まず、一文字のエリアス名は使わない。

別にいいじゃんって思うかもしれませんが、Javaで一文字の変数名を付けるかっていったら、(特別なケース以外は)付けないじゃないですか?

それと同じです。逆に、SQLで一文字のエリアス名を付けるなら、Javaでも付けるかなって感じ。

でも、SQLの本のサンプルとか見るとたくさんありますよね。まあ世の習慣ってところで仕方ないですが、単にぼくはあまりやらないかなと。

どちらかというと、コンパイルセーフではないSQLの方が、少しでも視認性が高い方がうれしいので最低二文字みたいな。

適度な省略文字

適度な省略文字を使います。ちょっと前までは、わりと service とか withdrawal とか本当にJavaの変数名みたいに省略無しの単語を使ったりしてましたが、こっちは世の習慣に負けたみたいな。。。笑。まあ、確かにSQLでかくなっちゃうので省略するようにしました。

ただ、これって本当は、何も考えずに省略は良くないんですよね。皆が思い思いの省略文字を使うと「省略の仕方」にブレが生じて統一的でなくなるって。プロジェクトで省略文字が決まってたりしていれば、それに従います。が、あんまりそういうのしっかりしてるプロジェクトって最近見かけないので、感性でやっちゃってます。

DBFlute使ってるプロジェクトであれば、そもそも外だしSQLが少ないので、まあ、その辺は強く堅くやらなくてもそんなに困りません。
そう、そういう面でもDBFluteは考えてます。SQLをベタにすべて書くとなると、「SQLのコーディング規約」をちゃんと作らないと、
そーとーカオスになる。Javaだとわりと世に統一的な書き方が浸透しているし、IDEによるフォーマッティングとかもあるけど、

SQLは10人に書かせたら10色のSQL

そしてそして、「SQLのコーディング規約」を作っても、なかなか守ってもらえない(><

だから ConditionBean ってわけではありませんが、(メインに主張してる概念はもっと別なので)ただただ、意外にあまり議論されない、「SQLが抱えるシステム開発における問題」だと切に思うのです。(バラバラのSQLをメンテするって、本当に大変ですよ!)

文字数を変えるテクニック

時折、文字数を変える。

わざと文字数を変えて「でこぼこ」になるようにしたりします。文字数が統一されている方が一瞬綺麗に見えますが、それは実は「違うものが同じように見えて綺麗に見える」という罠。

常にというわけじゃないですが、感覚的に...「これとこれは違う文字数にしたい」ってピーンって感じたときにそうします。

さらに識別が必要なら...

で、違う STATUS が混じるようであれば、mbStat とかにするかも。なんというか、Javaの変数名のような感覚です。あとでリファクタリングもするかもしれないし。

そう、サービスの開発とかだと、SQLはインクリメンタルに何度も修正&追加していくので、あとでリファクタリングしやすいようにしておく、っていうのをなんとなく意識します。

そうですね...普段は自分の周りでは ConditionBean 使ってるので、変更耐性強いですが、「変更や追加に強いSQLの書き方」っていうの、あまり確立されたセオリーあまり見たことないですね。ちょっと色々考えてみるとおもしそうかな!?

結局は好みなんだけどー

まあもう、SQLの世界では、

「こうあるべきだ」

ってのは絶対に通用しないのはわかっているのですが...
(文化、習慣がいたるところで違うので)

頭文字方式にデメリットがあるのは事実だと思うので、使うなら使うでそのデメリットを回避する何かしらの意識があればいいかなと。

特にこだわりがなく共感を持ってもらえたのであれば、実践してみはいかかでしょう?

DBFluteハンズオンでも、「こだわりのやり方があればそれでOKで、なければこういうセオリーがあるので試してみてください」
みたいな感じで伝えています(^^。(その現場の文化がある場合はそっちを優先してもらいますが...)

SQLのライフサイクル

【追記】(2014/09/10)
SQLって「その場限りSQL」を書くこともあるので、そのときの感覚と混じるケースが多いのかもしれないと思いました。

「その場限りSQL」だったら何も考える必要はないかと。ただ、同じノリで「継続メンテするSQL」を書いてしまうと、ちょっと変な感じになってしまう。

というか、そういう「SQLのライフサイクル」を区別してSQLを書く人の方が少ないかも知れません。SQLの議論をするときは、そこは明確にした方がいいかもですね。