TSQLの解析1 SELECT文からのテーブル名の取得

# 前提
- 対象  
MicrosoftのTSQL(Transact-SQL)
- 環境  
Microsoft Windows
- ツール 
 - SQL構文解析プログラム  
     - TSQLScriptDomParser  
https://github.com/GCer-Hidenori/TSQLScriptDomParser
     - ANTSQLParser  
https://github.com/GCer-Hidenori/ANTSQLParser
 - XSLT変換
     - SAXON: The XSLT and XQuery Processor  
      http://saxon.sourceforge.net/

# SELECT文からのテーブル名の取得
## TSQLScriptDomParser
### fromのテーブル名の一覧を取得  
- 実行例

```batchfile
sqlparser -o xml -i -s "select * from db1.schema1.tab1"  > out.xml
query -s:out.xml -qs://node[@class='FromClause']/children[@type='TableReferences']/node[@class='NamedTableReference']/children[@type='SchemaObject']/node[@class='SchemaObjectName']/children[@type='BaseIdentifier']/node !indent=true
```
- 出力例

```xml
<?xml version="1.0" encoding="UTF-8"?>
<node token="tab1"
      class="Identifier"
      value="tab1"
      QuoteType="NotQuoted"/>
```
- 解釈  
テーブルの数だけnode要素が出力される。  
node要素のvalue属性がテーブル名。

### DB名/スキーマ名も取得する
- 実行例

```batchfile
sqlparser -o xml -i -s "select * from db1.schema1.tab1"  > out.xml
query -s:out.xml -qs://node[@class='FromClause']/children[@type='TableReferences']/node[@class='NamedTableReference']/children[@type='SchemaObject']/node[@class='SchemaObjectName'] !indent=yes
```

- 出力例

```xml
<?xml version="1.0" encoding="UTF-8"?>
<node token="db1.schema1.tab1" class="SchemaObjectName" value="">
   <children type="DatabaseIdentifier">
      <node token="db1"
            class="Identifier"
            value="db1"
            QuoteType="NotQuoted"/>
   </children>
   <children type="SchemaIdentifier">
      <node token="schema1"
            class="Identifier"
            value="schema1"
            QuoteType="NotQuoted"/>
   </children>
   <children type="BaseIdentifier">
      <node token="tab1"
            class="Identifier"
            value="tab1"
            QuoteType="NotQuoted"/>
   </children>
   <children type="Identifiers">
      <node token="db1"
            class="Identifier"
            value="db1"
            QuoteType="NotQuoted"/>
      <node token="schema1"
            class="Identifier"
            value="schema1"
            QuoteType="NotQuoted"/>
      <node token="tab1"
            class="Identifier"
            value="tab1"
            QuoteType="NotQuoted"/>
   </children>
</node>
```

- 解釈 
 
|項目|値|
|:--|:--|
|サーバ名|/node/children[@type='ServerIdentifier']/node のvalue属性|
|データベース名|/node/children[@type='DatabaseIdentifier']/node のvalue属性|
|スキーマ名|/node/children[@type='SchemaIdentifier']/node のvalue属性|
|テーブル名|/node/children[@type='BaseIdentifier']/node のvalue属性|



### joinのテーブル名の一覧を取得
- 実行例

```batchfile
sqlparser -o xml -i -s "select * from db1.schema1.tab1 join db2.schema2.tab2 on tab1.id=tab2.id"  > out.xml
query -s:out.xml "-qs://node[@class='QualifiedJoin']/children[@type='FirstTableReference' or @type='SecondTableReference']/node[@class='NamedTableReference']/children[@type='SchemaObject']/node[@class='SchemaObjectName']" !indent=true
```

- 出力例

```xml
<?xml version="1.0" encoding="UTF-8"?>
<node token="db1.schema1.tab1" class="SchemaObjectName" value="">
   <children type="DatabaseIdentifier">
      <node token="db1"
            class="Identifier"
            value="db1"
            QuoteType="NotQuoted"/>
   </children>
   <children type="SchemaIdentifier">
      <node token="schema1"
            class="Identifier"
            value="schema1"
            QuoteType="NotQuoted"/>
   </children>
   <children type="BaseIdentifier">
      <node token="tab1"
            class="Identifier"
            value="tab1"
            QuoteType="NotQuoted"/>
   </children>
   <children type="Identifiers">
      <node token="db1"
            class="Identifier"
            value="db1"
            QuoteType="NotQuoted"/>
      <node token="schema1"
            class="Identifier"
            value="schema1"
            QuoteType="NotQuoted"/>
      <node token="tab1"
            class="Identifier"
            value="tab1"
            QuoteType="NotQuoted"/>
   </children>
</node>
<node token="db2.schema2.tab2" class="SchemaObjectName" value="">
   <children type="DatabaseIdentifier">
      <node token="db2"
            class="Identifier"
            value="db2"
            QuoteType="NotQuoted"/>
   </children>
   <children type="SchemaIdentifier">
      <node token="schema2"
            class="Identifier"
            value="schema2"
            QuoteType="NotQuoted"/>
   </children>
   <children type="BaseIdentifier">
      <node token="tab2"
            class="Identifier"
            value="tab2"
            QuoteType="NotQuoted"/>
   </children>
   <children type="Identifiers">
      <node token="db2"
            class="Identifier"
            value="db2"
            QuoteType="NotQuoted"/>
      <node token="schema2"
            class="Identifier"
            value="schema2"
            QuoteType="NotQuoted"/>
      <node token="tab2"
            class="Identifier"
            value="tab2"
            QuoteType="NotQuoted"/>
   </children>
</node>
```

- 解釈

|項目|値|
|:--|:--|
|サーバ名|/node/children[@type='ServerIdentifier']/node のvalue属性|
|データベース名|/node/children[@type='DatabaseIdentifier']/node のvalue属性|
|スキーマ名|/node/children[@type='SchemaIdentifier']/node のvalue属性|
|テーブル名|/node/children[@type='BaseIdentifier']/node のvalue属性|

### 副問合せで使われるSELECT文からのテーブル名の取得
同じ実行方法で、同じ方法で解釈。

### 注意
with句や副問合せでのaliasもテーブル名として扱われる。

## ANTSQLParser  
### from/joinのテーブル名の一覧を取得  
- 実行例

```batchfile
sqlparser -o xml -i -s "select * from db1.schema1.tab1"  > out.xml
query -s:out.xml -qs://node[@rule='table_source']/node[@rule='table_source_item_joined']/node[@rule='table_source_item']/node[@rule='table_name_with_hint']/node[@rule='schema_object_name']/node[@rule='table_name']/node[@rule='id']/node[@rule='simple_id']/node[@token='ID'] !indent=true

```
- 出力例

```xml
<?xml version="1.0" encoding="UTF-8"?>
<node token="ID" rule="" value="tab1"/>
```
- 解釈  
テーブルの数だけnode要素が出力される。  
node要素のvalue属性がテーブル名。

### DB名/スキーマ名も取得する
- 実行例

```batchfile
sqlparser -o xml -i -s "select * from db1.schema1.tab1"  > out.xml
query -s:out.xml -qs://node[@rule='table_source']/node[@rule='table_source_item_joined']/node[@rule='table_source_item']/node[@rule='table_name_with_hint']/node[@rule='schema_object_name'] !indent=true

```

- 出力例

```xml
<?xml version="1.0" encoding="UTF-8"?>
<node token="" rule="schema_object_name" value="db1.schema1.tab1">
   <node token="" rule="database_name" value="db1">
      <node token="" rule="id" value="db1">
         <node token="" rule="simple_id" value="db1">
            <node token="ID" rule="" value="db1"/>
         </node>
      </node>
   </node>
   <node token="'.'" rule="" value="."/>
   <node token="" rule="schema_name" value="schema1">
      <node token="" rule="id" value="schema1">
         <node token="" rule="simple_id" value="schema1">
            <node token="ID" rule="" value="schema1"/>
         </node>
      </node>
   </node>
   <node token="'.'" rule="" value="."/>
   <node token="" rule="table_name" value="tab1">
      <node token="" rule="id" value="tab1">
         <node token="" rule="simple_id" value="tab1">
            <node token="ID" rule="" value="tab1"/>
         </node>
      </node>
   </node>
</node>
```

- 解釈 
 
|項目|値|
|:--|:--|
|サーバ名|/node/node[@rule='server_name']//node[@token='ID']のvalue属性|
|データベース名|/node/node[@rule='database_name']//node[@token='ID']のvalue属性|
|スキーマ名|/node/node[@rule='schema_name']//node[@token='ID']のvalue属性|
|テーブル名|/node/node[@rule='table_name']//node[@token='ID']のvalue属性|

### 副問合せで使われるSELECT文からのテーブル名の取得
同じ実行方法で、同じ方法で解釈。

### 注意
with句や副問合せでのaliasもテーブル名として扱われる。

# ツールの簡単な説明
- TSQLScriptDomParser 
Microsoftの[Microsoft SQL Server 2016 Service Pack 2 Feature Pack](https://www.microsoft.com/ja-jp/download/details.aspx?id=56833)に入っているMicrosoft SQL Server 2016 SP2 Transact-SQL ScriptDomをベースに作成。
SQL Server 2019等の最新の構文には対応していない。 
構文の仕様は[Microsoftのライブラリのリファレンス](https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.sqlserver.transactsql.scriptdom)を参照。

- ANTSQLParser 
antlr4の[TSQLの構文のサンプル](https://github.com/antlr/grammars-v4/tree/master/sql/tsql)をベースに作成。 
SQL Server 2019等の最新の構文には、作者が対応させたもの以外は対応していない。 
ベースから引き継いだ細かな不具合が多くある。 
ただし文法ファイル（ [TSqlParser.g4](https://github.com/GCer-Hidenori/ANTSQLParser/blob/master/LibTSQL/TSqlParser.g4) [TSqlLexer.g4](https://github.com/GCer-Hidenori/ANTSQLParser/blob/master/LibTSQL/TSqlLexer.g4)　）が有るので仕様が明瞭。