Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8899

ScriptDom を利用して SQL文字列 を 編集する部品を作ってみた話②

$
0
0

ここまでのあらすじ

ScriptDom っていう、SQLを編集するためのライブラリがあるらしい。
これを使って、複数のクエリを集合演算子でUNIONしたりできる部品を作ってみたよ。

前回の記事はこちら↓
https://qiita.com/K-Z/items/a0a85a8498f0baaa94be

ScriptDom
https://www.nuget.org/packages/Microsoft.SqlServer.TransactSql.ScriptDom/15.0.4200.1

実際の開発で動的にSQLを編集したいシーンってどんなとき?

一番多いのは画面入力などの外部入力に応じてWHERE句に条件を追加したりするときだと思います。
ついで、ソート順をいじくりたいときかな……。
そういう訳で、今回はWHERE句の編集ができるように部品に機能追加をしていきます。

前回同様、コードの解説は少なめです。
ご承知おきください。

さて、イメージとしては、こんな感じのコードでWHERE句に条件式を追加出来るようにしたいのだが……。

usingKzLib.SqlServer.TransactSql.ScriptDom;////////////// (中略) ////////////////stringbaseSql=@"SELECT
   Foo1.Bar1
FROM Foo
WHERE
    Foo1.Bar1 = 1";TransactSQLtSQL=TransactSQL.Parse(baseSql);tSQL.Items[0].WhereClause.Items.Add(newWhereItem(@"Foo1.Bar2 = '2'",BooleanBinaryExpressionType.And));System.Diagnostics.Debug.Write(tSQL.ToString());

SQLの一部分をパースする

さて、この要件を満たすには、後から追加する条件式の文字列をパース出来る必要があります。
このようなSQLスクリプトの一部分をパースするためのAPIもScriptDomにはいくつか存在します。
今回使うのは、

TSql150Parser.ParseBooleanExpression

メソッドです。
これが、条件式をパースするためのメソッドになります。
もうひとつ、左右の値を比較するような条件式を書くときに、定数値やら、Hoge.Huga のようなテーブルの列の値を記述したりします。
これは、

TSql150Parser.ParseExpression

メソッドを使うとパースできます。

条件式の構造

さて、条件式はパースした結果、どのように格納されているのでしょう。

前回、クエリを UNION で結合する部品を作ったときには、クエリがツリー上に格納されていました。
やはり、WHERE句の条件式もこれと同様にツリー上に格納されています。

条件式を表すクラスの親玉として、
BooleanExpression
というクラスがあり、条件式の種類に応じてそのサブクラスがいくつかあります。

BooleanExpression
https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.sqlserver.transactsql.scriptdom.booleanexpression?view=sql-dacfx-140.3881.1

これらのサブクラスのうち今回の目的で特に重要なのは、BooleanBinaryExpression と、BooleanParenthesisExpression です。
前者は2つの条件式を And や Or で繋ぐ論理演算を表します。
後者は条件式中の1部を優先的に評価すること(つまり、括弧の役割)を表します。

例えば次のようなSQLのWhere句

WHEREHoge1.Huga1=1--条件式(1)AND(Hoge1.Huga1=2--条件式(2)ORHoge1.Huga1=3--条件式(3)ORHoge1.Huga1=4--条件式(4))

これをパースすると、WHERE句は以下のようなイメージの式ツリーになります。

  • BooleanBinaryExpression(And)
    • 条件式(1)
    • BooleanParenthesisExpression
      • BooleanBinaryExpression(Or)
        • 条件式(2)
        • BooleanBinaryExpression(Or)
          • 条件式(3)
          • 条件式(4)

例によって無駄に(?)階層が深くなって人間には分かりにくく、編集しづらそうです。
人間に分かりやすくするなら、こんな感じでしょうか。

  • 条件式(1)
  • (AND)
    • 条件式(2)
    • (OR)条件式(3)
    • (OR)条件式(4)

ということで……。

おわりに

そんなこんなで、必要なAPIや目標とする部品のイメージは判明したので、それを作ったものがこちらになります(3分クッキング)。

https://github.com/8810hayate/TransactSQL

ところで、BooleanExpression のサブクラスを眺めていると、役割が名前からすぐに分かるものと分からない物がありました。
調べてみると、意外と普段何気なく使っているSQLにも知らない構文があったりしそうだなぁと感じました。


Viewing all articles
Browse latest Browse all 8899

Trending Articles