T sql の parse と generator

41
T-SQL の Parse の Generate 2013/03/23 SQLWorld のの #12 SQLWorld の の

Transcript of T sql の parse と generator

Page 1: T sql の parse と generator

T-SQL の Parse と Generate

2013/03/23 SQLWorld 大阪 #12SQLWorld お だ

Page 2: T sql の parse と generator

自己紹介

織田 信亮大阪で開発者していますSQLWorld の代表です

http://d.hatena.ne.jp/odashinsuke/Twitter:@shinsukeoda

Page 3: T sql の parse と generator

アジェンダ

Parse と Generate って?どうやるの?何に使える?使ってみた!まとめ

Page 4: T sql の parse と generator

このセッションの注意事項

全ての機能は紹介出来ません!紹介するライブラリでは、 1000 近くの Class, 200 近くの Enum がある簡単な Parse と Generate に絞ってます。

Page 5: T sql の parse と generator

Parse と Generate って?どうやるの?何に使える?使ってみた!まとめ

Page 6: T sql の parse と generator

Parse と Generate

Parse ( パース )SQL 文 => 構文毎に分解したデータ構造の集まり

Generate ( ジェネレート )構文毎のデータ構造の集まり => SQL 文

Page 7: T sql の parse と generator

クエリ

SELECT 句

列 1 列 2

FROM 句

テーブル

SELECT 列 1, 列2 FROM テーブル

Parse

Page 8: T sql の parse と generator

クエリ

SELECT 句

列 1 列 2

FROM 句

テーブル

SELECT 列 1, 列2 FROM テーブル

Generate

Page 9: T sql の parse と generator

Parse と Generate

Parse ( パース )SQL 文 => 構文毎に分解したデータ構造の集まり

Generate ( ジェネレート )構文毎のデータ構造の集まり => SQL 文

Parser ( パーサー )Parse してくれる便利なやつ

Generator ( ジェネレーター )Generate してくれる良いやつ

Page 10: T sql の parse と generator

Parser と Generator

MS から .NET Framework のライブラリとして提供Microsoft.SqlServer.TransactSql.ScriptDom 名前空間

1 世代前は…Microsoft.Data.Schema.ScriptDomMicrosoft.Data.Schema.ScriptDom.Sql

SQL Server 2012 Feature Pack の 「 Transact-SQL ScriptDom 」 をインストール

SQL Server は不要

Page 11: T sql の parse と generator

Parse と Generate って?どうやるの?何に使える?使ってみた!まとめ

Page 12: T sql の parse と generator

インストール

Microsoft SQL Server 2012 Feature Packhttp://www.microsoft.com/ja-jp/download/details.aspx?id=29065

Page 13: T sql の parse と generator

準備

参照の追加Microsoft.SqlServer.TransactSql.ScriptDom

Page 14: T sql の parse と generator

Parse してみる

TSqlParser クラスParse メソッドを使う

using Microsoft.SqlServer.TransactSql.ScriptDom;using System.Collections.Generic;using System.IO;

var parser = new TSql110Parser(false);IList<ParseError> errors;TSqlFragment parsed;using (var query = new StringReader("select * from Table1")) { parsed = parser.Parse(query, out errors);}

Page 15: T sql の parse と generator

Parse してみる ( エラー )

ParseError クラスLine, Column, Message プロパティから行、文字位置、エラー内容を取れる

if (errors.Count != 0) { foreach (var error in errors) { System.Console.WriteLine("{0} 行目 {1} 文字目 {2}", error.Line, error.Column, error.Message); }}

Page 16: T sql の parse と generator

Generate してみる

SqlScriptGenerator クラスGenerateScript メソッドを使う

var options = new SqlScriptGeneratorOptions() { KeywordCasing = KeywordCasing.Uppercase, IncludeSemicolons = true, NewLineBeforeFromClause = true, NewLineBeforeOrderByClause = true, NewLineBeforeWhereClause = true};var generator = new Sql110ScriptGenerator(options);string generated;generator.GenerateScript(parsed, out generated);

Page 17: T sql の parse と generator

もうちょっと細かいとこまで

Parser – バージョン毎に用意されてるTSql80Parser - SQL Server 2000 用TSql90Parser - SQL Server 2005 用TSql100Parser - SQL Server 2008 用TSql110Parser - SQL Server 2012 用

バージョンが違うとエラーになる構文も…

Page 18: T sql の parse と generator

もうちょっと細かいとこまで

Parse 結果TSqlFragment – 基底クラスTSqlScript, TSqlBatch, TSqlStatement, SelectElement, FromClause, WhereClause, Identifier, CreateTableStatement, 等々 800 個近い継承したクラスがあるDML に限らず、 DDL や DBCC 等の全ての T-SQL に対応している「はず!」

Visitor パターンになっているので、 Visitor を実装すれば色々出来る

Page 19: T sql の parse と generator

もうちょっと細かいとこまで

Visitorどちらかのクラスを継承し、目的の Visitor メソッドを override するTSqlFragmentVisitor

呼び出される Visitor メソッドのパラメータは継承した物も含む

TSqlConcreteFragmentVisitorVisitor メソッドのパラメータ型は厳密

Page 20: T sql の parse と generator

もうちょっと細かいとこまで

例: SELECT で指定している項目の数を数えるhttp://msdn.microsoft.com/ja-jp/library/microsoft.sqlserver.transactsql.scriptdom.selectelement.aspx

SELECT @Id = A.Id, @Name = B.Name FROM ( SELECT * FROM Table1 WHERE Id = 1) A INNER JOIN Table2 B ON ( A.USERID = B.ID )

Page 21: T sql の parse と generator

もうちょっと細かいとこまで

TSqlFragmentVisitorSELECT で指定している項目全ての件数を数える Visitor

public class SelectElementVisitor : TSqlFragmentVisitor { public int Count { get; set; } public override void Visit(SelectElement node) { Count++; base.Visit(node); }}

Page 22: T sql の parse と generator

もうちょっと細かいとこまで

TSqlConcreteFragmentVisitorSELECT で指定している “ *” の件数を数える Visitor

public class SelectStarVisitor : TSqlFragmentVisitor { public int Count { get; set; } public override void Visit(SelectStarExpression node) { Count++; base.Visit(node); }}

Page 23: T sql の parse と generator

もうちょっと細かいとこまで

カスタム Visitor を利用するvar q = @"SELECT @Id = A.Id, @Name = B.Name FROM ( SELECT * FROM Table1 WHERE Id = 1) A INNER JOIN Table2 B ON ( A.USERID = B.ID )";var f = new TSql110Parser(false)   .Parse(new StringReader(q), out errors);

var v1 = new SelectElementVisitor();var v2 = new SelectStarVisitor();f.Accept(v1);f.Accept(v2);

Console.WriteLine(v1.Count); // 3Console.WriteLine(v2.Count); // 1

Page 24: T sql の parse と generator

もうちょっと細かいとこまで

Generator – バージョン毎に用意されてるSql80ScriptGenerator - SQL Server 2000 用Sql90ScriptGenerator - SQL Server 2005 用Sql100ScriptGenerator - SQL Server 2008 用Sql110ScriptGenerator - SQL Server 2012 用

イマイチ違いが判らず…

Page 25: T sql の parse と generator

もうちょっと細かいとこまで

TSqlFragment を組み立てて、クエリを生成する

「もうちょっと」 で済まないくらい大変!!

お勧めはしないhttp://d.hatena.ne.jp/odashinsuke/20130224/1361714459

Page 26: T sql の parse と generator

裏では何使ってるの?

antlr を使ってると思いますhttp://www.antlr.org/

Page 27: T sql の parse と generator

Parse と Generate って?どうやるの?何に使える?使ってみた!まとめ

Page 28: T sql の parse と generator

MSDN に掲載されているサンプル

チュートリアル : SQL 用のカスタムの静的コード分析規則アセンブリを作成する

http://msdn.microsoft.com/ja-jp/library/dd172127%28v=vs.100%29.aspx

Visual Studio 2008/2010 でのコード解析 で 「 WAITFOR DELAY 」 が使用されているか検出するチュートリアル

Page 29: T sql の parse と generator

何に使えるの?

アイデア募集中!

Page 30: T sql の parse と generator

何に使えるの?

クエリの検証構文エラーの検出コーディング規約のチェック

クエリの書式設定 / 統一クエリの部分抽出動的なクエリ生成

クエリの改造

Page 31: T sql の parse と generator

クエリの検証

構文エラーの検出実 DB が無い環境でも SQL の構文が正しいか判定出来る注意点としてオブジェクトの存在チェックは出来ない!

SQL Server のバージョン毎に構文チェックが可能なので、移行検証時に使えるかもSQL Server の Ver UP や 他社 DB (Oracle 等 ) からの移行

Page 32: T sql の parse と generator

クエリの検証

コーディング規約のチェック例えば…DELETE は使わない ( 論理削除 )マスタテーブル (MST_ ~ ) は inner join とか

漏れやすい項目の検証SELECT 文に ORDER BY が存在していないクエリの検出スキーマ指定漏れ定型的な条件の漏れ (DELETE_FLG = 0 とか )COLLATE 指定

Page 33: T sql の parse と generator

クエリの書式設定 / 統一

クエリのフォーマットキーワードの大文字 / 小文字化識別子の [] 囲みインデント改行

Page 34: T sql の parse と generator

クエリの部分抽出

サブクエリだけ抜き出すSELECT の結果カラムだけ抜き出すINSERT – SELECT から SELECT だけ抜き出す

INSERT 実行前に更新対象を確認 ( クエリ自体は 1 つで可能 )

Page 35: T sql の parse と generator

動的なクエリ生成

クエリの改造ER => DDL (CREATE TABLE) で共通的なカラムの追加SELECT で共通的なカラムの追加COUNT(*) OVER() AS [ 全件数 ]

INSERT/UPDATE で共通的なカラムの追加更新日 / 更新者 等

Page 36: T sql の parse と generator

Parse と Generate って?どうやるの?何に使える?使ってみた!まとめ

Page 37: T sql の parse と generator

ScriptDom のサンプルサイト

ScriptDom Samplehttp://scriptdomsample.azurewebsites.net/クエリの書式設定 / 統一クエリの部分抽出クエリの改造

Page 38: T sql の parse と generator

ビルド時の SQL 検証

MSBuild のタスクとして作成するプロジェクト内に存在する .sql ファイルで SELECT 文の物を対象に ORDER BY が存在しなかったらエラーとする

Page 39: T sql の parse と generator

まとめ

T-SQL には、 MS 公式の Parser/Generator があるSQL Server 2000, 2005, 2008, 2012 の 4 バージョン面白そうではあるけど、どこで / 何に使うのかはアイデアが要るかも

Page 40: T sql の parse と generator

参考資料

Microsoft SQL Server 2012 Feature Packhttp://www.microsoft.com/ja-jp/download/details.aspx?id=29065

Microsoft.SqlServer.TransactSql.ScriptDom 名前空間http://msdn.microsoft.com/ja-jp/library/hh215705.aspx

Visual Studio のデータベース機能の API リファレンスhttp://msdn.microsoft.com/ja-jp/library/dd193281(v=vs.100).aspx

ANTLRhttp://www.antlr.org/

Page 41: T sql の parse と generator

参考資料 (ScriptDom を使ってる )

チュートリアル : SQL 用のカスタムの静的コード分析規則アセンブリを作成するhttp://msdn.microsoft.com/ja-jp/library/dd172127%28v=vs.100%29.aspx

SQLPSX (PowerShell2 系 /1 世代前の ScriptDom)http://sqlpsx.codeplex.com/