
Pythonで様々なSQL処理を行えるSQLGlotの機能を試してみる
はじめに
データアナリティクス事業本部のkobayashiです。
Pythonでクエリをパースしてその内容を扱う場合にはいろいろなライブラリがあります。以前、sql-metadata というライブラリを紹介しましたが、今回はPythonのSQLパーサー・トランスパイラーであるSQLGlotを使ってみたいと思います。SQLGlotはパーサーの他にもトランスパイラー、オプティマイザー、エンジン変換の機能を持つライブラリで、特に変換に関しては30種類以上のSQLエンジンをサポートする強力なライブラリで、異なるデータベース間でのSQL移植作業を大幅に簡素化できます。パーサー、フォーマット機能、SQLエンジン間の変換機能について試してみます。
SQLGlotとは
SQLGlotは外部依存関係のないPure PythonのSQLパーサー、トランスパイラー、オプティマイザー、およびエンジンです。主な特徴として以下があります。
- 30種類以上のSQLエンジンをサポート(Redshift、BigQuery、Snowflake、DuckDB、Hive、MySQL、PostgreSQLなど)
- 構文的に正しいSQLの出力を保証
- コメントを保持したままの変換が可能
- 高いパフォーマンスとメモリ効率
インストール
SQLGlotのインストールは非常に簡単でpipでインストールします。
pip install sqlglot
基本的な使い方
SQLのパース
SQLGlotを使用すると、SQLをパースして抽象構文木(AST)を取得できます:
import sqlglot
from sqlglot import exp
sql = """
SELECT
u.user_name,
p.product_name,
s.sale_date
FROM
sales AS s
JOIN
users AS u ON s.user_id = u.id
LEFT JOIN
products p ON s.product_id = p.id
WHERE
s.amount > 1000
"""
ast = sqlglot.parse_one(sql)
# すべてのテーブル名(エイリアスも含む)を抽出
tables = {table.name for table in ast.find_all(exp.Table)}
print(f"使われているテーブル: {tables}")
# すべてのカラム名を抽出
columns = {column.name for column in ast.find_all(exp.Column)}
print(f"使われているカラム: {columns}")
使われているテーブル: {'sales', 'products', 'users'}
使われているカラム: {'product_name', 'id', 'user_id', 'product_id', 'sale_date', 'user_name', 'amount'}
このような形で、SQLGlotを使用することで、SQLクエリの解析を行ってテーブル名やカラムを取得できます。
SQLのフォーマット
SQLGlotを使用すると、読みにくいSQLクエリを整形できます:
import sqlglot
# フォーマット前のSQL
ugly_sql = "SELECT id,name,created_at FROM users WHERE status='active' ORDER BY created_at DESC"
# フォーマット
formatted_sql = sqlglot.parse_one(ugly_sql).sql(pretty=True)
print(formatted_sql)
SELECT
id,
name,
created_at
FROM users
WHERE
status = 'active'
ORDER BY
created_at DESC
フォーマットもオプションで指定できるため、フォーマットを行っても読みやすい形式にすることも可能です。
SQLエンジン間の変換(トランスパイル)
異なるデータベース間でSQLを変換する場合、SQLGlotのtranspile機能を使うことでそれぞれのエンジンに合わせたSQLを生成することができます。
import sqlglot
# DuckDBの構文からHiveの構文へ変換
duckdb_sql = "SELECT EPOCH_MS(1618088028295)"
hive_sql = sqlglot.transpile(duckdb_sql, read="duckdb", write="hive")
print(hive_sql[0])
# PostgreSQLからBigQueryへの変換
postgres_sql = "SELECT NOW()::DATE"
bigquery_sql = sqlglot.transpile(postgres_sql, read="postgres", write="bigquery")
print(bigquery_sql[0])
SELECT FROM_UNIXTIME(1618088028295 / 1000)
SELECT CAST(CURRENT_TIMESTAMP() AS DATE)
注意点と制限事項
SQLGlotも全能ではないのでを使用する際には、次の点に注意する必要があります。
- 完全な互換性は保証されない
- 特定のデータベース固有の機能は変換できない場合がありました。またストアドプロシージャやトリガーの変換は限定的なので注意が必要です。
- パフォーマンスの考慮
- 変換後のクエリが最適でない場合があるので気になる場合は実行計画の確認を行ったほうが良いです。
- セマンティクスの違い
- NULL値の扱いなど、データベース間で動作が異なる場合があります。
まとめ
SQLGlotは、パーサー機能、フォーマット機能、異なるSQLエンジン間での変換機能なと作業を大幅に効率化できる強力なツールです。データベース移行プロジェクトやマルチデータベース対応のアプリケーション開発において、SQLGlotを活用することで開発効率を大きく向上させることができます。
ただし、完全な自動変換に頼るのではなく、重要なクエリについては変換結果の検証とチューニングを行うことが重要かと思います。
最後まで読んで頂いてありがとうございました。