Обнаружение схем с помощью mssql-python

Класс курсора mssql-python предоставляет девять методов метаданных, соответствующих функциям каталога ODBC. Используйте эти методы для программного поиска таблиц, столбцов, хранящихся процедур, ключей и индексов. Они помогают создавать приложения, основанные на данных, которые адаптируются к схеме базы данных во время выполнения, такие как инструменты миграции, генераторы кода или администраторские панели.

Метод Функция ODBC Returns Когда использовать
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)

параметры таблиц()

Следующие параметры управляют обнаружением таблиц:

Parameter Описание
table Шаблон имени таблицы (поддерживает подстановочные знаки % и _).
catalog Название каталога (базы данных).
schema Схема названий.
tableType Фильтруйте по типу: TABLE, VIEW, SYSTEM TABLE, GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIASSYNONYM, .

таблицы() столбцы результатов

tables() Метод возвращает следующие столбцы для каждой таблицы или представления:

Column Описание
table_cat Название каталога (базы данных).
table_schem Имя схемы.
table_name Имя таблицы или представления.
table_type TABLE, VIEW, SYSTEM TABLE, GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, . SYNONYM
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()

Фильтры для уточнения поиска столбцов:

Parameter Описание
table Шаблон названий таблицы.
catalog Название каталога (базы данных).
schema Схема названий.
column Шаблон названий столбцов.

columns() столбцы результатов

Метод columns() возвращает подробную информацию о каждом столбце:

Column Описание
table_cat, table_schem, table_name Идентификаторы местоположения.
column_name Имя столбца.
data_type Код SQL-типа данных.
type_name Название типа данных (например, varchar, int).
column_size Максимальная длина или точность.
buffer_length Размер буфера для переносов.
decimal_digits Масштабирование для числовых типов.
nullable 0 для NOT NULL, 1 для допускающего значение NULL.
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)

параметры процедур()

Фильтруйте хранящиеся процедуры по имени или схеме:

Parameter Описание
procedure Шаблон названия процедуры.
catalog Название каталога (базы данных).
schema Схема названий.

процедуры() столбцы результатов

Метод возвращает procedures() метаданные для каждой сохранённой процедуры:

Column Описание
procedure_cat, procedure_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()

Параметры для получения информации о первичном ключе:

Parameter Описание
table Название таблицы (обязательно).
catalog Название каталога (базы данных).
schema Имя схемы.

Столбцы результатов primaryKeys()

primaryKeys()Метод возвращает следующую информацию:

Column Описание
table_cat, table_schem, table_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()

Укажите таблицы первичных или внешних ключей для поиска связей:

Parameter Описание
table Имя таблицы первичного ключа.
catalog Каталог первичных ключей.
schema Схема первичного ключа.
foreignTable Имя таблицы внешнего ключа.
foreignCatalog Каталог иностранных ключей.
foreignSchema Схема иностранных ключей.

Столбцы результатов foreignKeys()

foreignKeys() Метод возвращает следующие столбцы, описывающие отношения:

Column Описание
pktable_cat, pktable_schem, pktable_name Ссылка на (основную) таблицу.
pkcolumn_name Ссылаемый столбец.
fktable_cat, fktable_schem, fktable_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}")

параметры статистики()

Настройте обнаружение индексов с помощью следующих фильтров:

Parameter По умолчанию Описание
table (required) Имя таблицы.
catalog Нет Название каталога (базы данных).
schema Нет Имя схемы.
unique Неправда Возвращайте только уникальные индексы.
quick True Пропустите дорогостоящую кардинальность/поиск страниц.

статистика() столбцы результатов

Метод statistics() возвращает сведения об индексах и статистике:

Column Описание
table_cat, table_schem, table_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:

Parameter Описание
sqlType Константа типов SQL (опущено для всех типов).

Вопросы безопасности

Предостережение

Эти методы раскрывают метаданные схемы базы данных. Хотя сами методы безопасны в выполнении, возвращаемая информация раскрывает структуру вашей базы данных (имена таблиц, имена столбцов, отношения, типы данных).

  • Не раскрывайте необработанные метаданные недоверенным пользователям.
  • Очищайте или фильтруйте результаты в мультитенантных приложениях.
  • Ограничить доступ к приложениям, ориентированным наружу.

Пример: Сгенерировать отчёт по схеме

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")