mssql-pythonによるスキーマ発見

mssql-pythonカーソルクラスは、ODBCカタログ関数にマッピングされる9つのメタデータメソッドを提供します。 これらの手法を使って、テーブル、カラム、ストアドプロシージャ、キー、インデックスをプログラム的に発見できます。 彼らは、マイグレーションツール、コードジェネレーター、管理ダッシュボードなど、ランタイムでデータベーススキーマに適応するデータ駆動型アプリケーションの開発を支援します。

Method ODBC関数 返品 いつ使用するか
tables() SQLTables テーブルとビュー情報。 在庫データベース。 クエリの前にテーブルの存在を検証してください。
columns() SQLColumns コラムの詳細。 DDLを生成したり、動的なクエリを作成したり、列をコードにマッピングしたりできます。
procedures() SQLProcedures ストアドプロシージャ情報。 利用可能なAPIを発見しましょう。 プロシージャ呼び出しラッパーを生成します。
primaryKeys() SQLPrimaryKeys 主キー列。 UPDATE/DELETE操作のための一意な行識別子を特定します。
foreignKeys() SQLForeignKeys 外部キー リレーションシップ。 マップテーブルの関係を管理し、クリーンアップスクリプトの削除順を決定します。
statistics() SQLStatistics 索引および統計情報。 パフォーマンス調整のためにインデックスカバレッジを確認してください。
rowIdColumns() SQLSpecialColumns (ROWID) 一意の行識別子列。 特定の行を特定するのに最適な列を見つけましょう。
rowVerColumns() SQLSpecialColumns (ROWVER) 行バージョン列。 楽的並行性(同時修正の検出)を実装します。
getTypeInfo() SQLGetTypeInfo データ型情報。 クロスプラットフォーム互換性のためにサポートされているタイプを発見。

各メソッドはカーソルを返し、結果にアクセスするために反復処理できます。

Tables

データベース内のテーブルとビューのリスト:

cursor = conn.cursor()

# List all tables
for row in cursor.tables():
    print(f"{row.table_schem}.{row.table_name} ({row.table_type})")

# Filter by name (supports wildcards % and _)
for row in cursor.tables(table="Product%"):
    print(row.table_name)

# Filter by schema
for row in cursor.tables(schema="Sales"):
    print(row.table_name)

# Filter by type
for row in cursor.tables(tableType="TABLE"):  # Excludes views
    print(row.table_name)

tables() パラメータ

以下のパラメータはテーブルの発見を制御します:

パラメーター 説明
table テーブル名パターン( % および _ ワイルドカード対応)。
catalog カタログ(データベース)名。
schema スキーマ名パターン。
tableType タイプ別フィルター: TABLEVIEWSYSTEM TABLEGLOBAL TEMPORARYLOCAL TEMPORARYALIASSYNONYM

テーブル() 結果列

tables()メソッドは各テーブルまたはビューごとに以下の列を返します:

Column 説明
table_cat カタログ(データベース)名。
table_schem スキーマ名。
table_name テーブルまたはビューの名前。
table_type TABLEVIEWSYSTEM TABLEGLOBAL TEMPORARYLOCAL TEMPORARYALIASSYNONYM
remarks 説明やコメント。

テーブルが存在するかどうか確認してください

クエリする前にテーブルの存在を必ず確認してください:

if cursor.tables(table="Product", schema="Production").fetchone():
    print("Product table exists")
else:
    print("Product table not found")

テーブルの列情報を取得する:

# All columns in a table
for row in cursor.columns(table="Product", schema="Production"):
    print(f"{row.column_name}: {row.type_name}({row.column_size})")
    print(f"  Nullable: {row.nullable}, Position: {row.ordinal_position}")

# Filter by column name
for row in cursor.columns(table="Product", schema="Production", column="List%"):
    print(row.column_name)

columns() パラメータ

カラム発見を精準化するためのフィルター:

パラメーター 説明
table テーブル名パターン。
catalog カタログ(データベース)名。
schema スキーマ名パターン。
column 列名パターン。

columns() の結果列

columns()メソッドは各列の詳細情報を返します:

Column 説明
table_cattable_schemtable_name ロケーション識別子。
column_name 列名。
data_type SQLデータ型コード。
type_name データ型名(例: varcharint)。
column_size 最大の長さまたは精度。
buffer_length 転送用のバッファサイズ。
decimal_digits 数値タイプのためのスケール。
nullable 0 NOT NULLの場合は 1 、nullableは。
column_def 既定値。
ordinal_position 列の位置(1ベース)。
is_nullable "YES" または "NO"

ストアド プロシージャ

ストアド プロシージャを確認する:

# List all procedures
for row in cursor.procedures():
    print(f"{row.procedure_schem}.{row.procedure_name}")

# Filter by name pattern
for row in cursor.procedures(procedure="Get%"):
    print(row.procedure_name)

procedure() パラメータ

ストアドプロシージャを名前またはスキーマでフィルタリングする:

パラメーター 説明
procedure プロシージャ名のパターン。
catalog カタログ(データベース)名。
schema スキーマ名パターン。

procedure() 結果列

procedures()メソッドは各ストアドプロシージャのメタデータを返します:

Column 説明
procedure_catprocedure_schem ロケーション識別子。
procedure_name プロシージャ名。
num_input_params 入力パラメータの数。
num_output_params 出力パラメータの数。
num_result_sets 結果セットの数。
remarks Description.
procedure_type タイプインジケーター。

主キー

表の主キー列を取得する:

for row in cursor.primaryKeys(table="Product", schema="Production"):
    print(f"PK column: {row.column_name} (position {row.key_seq})")
    print(f"Constraint name: {row.pk_name}")

primaryKeys() パラメータ

主キー情報を取得するパラメータ:

パラメーター 説明
table テーブル名(必須)。
catalog カタログ(データベース)名。
schema スキーマ名。

primaryKeys() 結果列

primaryKeys()メソッドは以下の情報を返します。

Column 説明
table_cattable_schemtable_name ロケーション識別子。
column_name 主キーの列。
key_seq 多列キー(1ベース)での位置。
pk_name プライマリキー制約名。

外部キー

外国の主要な関係を発見する:

# Foreign keys from a table (outbound references)
for row in cursor.foreignKeys(table="SalesOrderDetail", schema="Sales"):
    print(f"FK {row.fk_name}:")
    print(f"  {row.fktable_name}.{row.fkcolumn_name}")
    print(f"  -> {row.pktable_name}.{row.pkcolumn_name}")

# Foreign keys to a table (inbound references)
for row in cursor.foreignKeys(foreignTable="Product", foreignSchema="Production"):
    print(f"{row.fktable_name} references Product")

foreignKeys() パラメータ

関係を発見するために主鍵または外部鍵テーブルを指定する:

パラメーター 説明
table 主キーテーブル名。
catalog 主キーカタログ
schema プライマリキースキーマ。
foreignTable 外部キー テーブル名。
foreignCatalog 外国鍵カタログ。
foreignSchema 外部鍵スキーマ。

foreignKeys() 結果列

foreignKeys()メソッドは関係性を表す以下の列を返します。

Column 説明
pktable_catpktable_schempktable_name 参照された(プライマリ)テーブル。
pkcolumn_name 参照される列。
fktable_catfktable_schemfktable_name (外国の)表を参照しています。
fkcolumn_name 参照欄。
key_seq 複数列キー内の位置。
update_rule UPDATE に対する操作。
delete_rule DELETE に対するアクション。
fk_name 外部キー制約名。
pk_name プライマリキー制約名。

指数と統計

表のインデックス情報を得る:

# All indexes on a table
for row in cursor.statistics(table="Product", schema="Production"):
    if row.index_name:  # Skip table statistics row
        print(f"Index: {row.index_name}")
        print(f"  Column: {row.column_name} (position {row.ordinal_position})")
        print(f"  Unique: {not row.non_unique}")

# Only unique indexes
for row in cursor.statistics(table="Product", schema="Production", unique=True):
    print(f"Unique index: {row.index_name}")

statistics() パラメータ

以下のフィルターでインデックスディスカバリを設定します:

パラメーター Default 説明
table ("必須") テーブル名。
catalog なし カタログ(データベース)名。
schema なし スキーマ名。
unique False ユニークなインデックスのみを返します。
quick True コストの高いカーディナリティやページ数の取得をスキップします。

statistics() の結果列

statistics()メソッドはインデックスおよび統計情報を返します:

Column 説明
table_cattable_schemtable_name ロケーション識別子。
non_unique 0 は一意、1 は非一意。
index_name インデックス名。
type インデックスタイプ。
ordinal_position インデックス内の列の位置。
column_name 列名。
asc_or_desc 昇順の場合は A、降順の場合は D
cardinality 行数の推定値。
pages ページ数。

行識別子列

行を一意に識別する列を見つけてください:

for row in cursor.rowIdColumns(table="Product", schema="Production"):
    print(f"Row ID column: {row.column_name} ({row.type_name})")

このメソッドは、主キーや一意インデックスのいずれかの行を一意に識別するための最良の列集合を返します。

行バージョン列

行の値が変わったときに自動的に更新される列を見つけてください。 行バージョンの列を使って楽観的な並行管理を行いましょう。行のバージョンを読み取り、変更を加え、現在の行バージョンが同じかどうかを確認してから書き込む方法です:

for row in cursor.rowVerColumns(table="Product", schema="Production"):
    print(f"Version column: {row.column_name}")

その結果には通常、楽観的同時実行制御に使用される rowversion/timestamp 列が含まれます。

データ型情報

サポートされているSQLデータ型に関する情報を得る:

# All supported types
for row in cursor.getTypeInfo():
    print(f"{row.type_name}: {row.data_type}")
    print(f"  Max size: {row.column_size}")
    print(f"  Nullable: {row.nullable}")

# Specific type
for row in cursor.getTypeInfo(sqlType=mssql_python.SQL_VARCHAR):
    print(f"VARCHAR max size: {row.column_size}")

getTypeInfo() パラメーター

サポートするSQL型をフィルタリングするためのオプションパラメータ:

パラメーター 説明
sqlType SQL 型定数(すべての型で省略)

セキュリティに関する考慮事項

Caution

これらの手法はデータベーススキーマのメタデータを公開します。 メソッド自体は安全に実行できますが、返される情報はデータベース構造(テーブル名、列名、リレーションシップ、データ型)を明らかにします。

  • 生のメタデータを信頼できないユーザーに公開しないでください。
  • サニタイズやフィルタリングはマルチテナントアプリケーションにつながります。
  • 外部向けアプリケーションのアクセスを制限しましょう。

例:スキーマレポートを生成する

def describe_table(conn, table_name):
    """Generate a schema description for a table."""
    cursor = conn.cursor()
    
    print(f"\n=== {table_name} ===\n")
    
    # Columns
    print("Columns:")
    for col in cursor.columns(table=table_name):
        nullable = "NULL" if col.nullable else "NOT NULL"
        print(f"  {col.column_name}: {col.type_name}({col.column_size}) {nullable}")
    
    # Primary key
    print("\nPrimary Key:")
    pk_cols = cursor.primaryKeys(table=table_name).fetchall()
    if pk_cols:
        pk_names = ", ".join(row.column_name for row in pk_cols)
        print(f"  {pk_cols[0].pk_name}: ({pk_names})")
    else:
        print("  (none)")
    
    # Foreign keys
    print("\nForeign Keys:")
    for fk in cursor.foreignKeys(table=table_name):
        print(f"  {fk.fk_name}: {fk.fkcolumn_name} -> {fk.pktable_name}.{fk.pkcolumn_name}")
    
    # Indexes
    print("\nIndexes:")
    for idx in cursor.statistics(table=table_name):
        if idx.index_name:
            unique = "UNIQUE " if not idx.non_unique else ""
            print(f"  {unique}{idx.index_name}: {idx.column_name}")

# Usage
describe_table(conn, "Product")