Descoberta de esquema com mssql-python

A classe de cursor do mssql-python fornece nove métodos de metadados que correspondem a funções do catálogo ODBC. Use esses métodos para descobrir tabelas, colunas, procedimentos armazenados, chaves e índices programaticamente. Eles ajudam a construir aplicações orientadas por dados que se adaptam ao esquema do banco de dados em tempo de execução, como ferramentas de migração, geradores de código ou painéis administrativos.

Método Função ODBC Returns Quando usar
tables() SQLTables Informações de tabela e visualização. Banco de dados de inventário. Valide a existência da tabela antes das consultas.
columns() SQLColumns Detalhes da coluna. Gerar DDL, construir consultas dinâmicas ou mapear colunas para código.
procedures() SQLProcedures Informações de procedimentos armazenados. Descubra as APIs disponíveis. Gerar encapsuladores de chamada de procedimento.
primaryKeys() SQLPrimaryKeys Colunas de chave primária. Identifique identificadores exclusivos de linha para operações de UPDATE/DELETE.
foreignKeys() SQLForeignKeys Relacionamentos estrangeiros-chave. Mapear relacionamentos de tabelas, determinar a ordem de exclusão dos scripts de limpeza.
statistics() SQLStatistics Informações de índice e estatísticas. Verifique a cobertura do índice para ajuste de desempenho.
rowIdColumns() SQLSpecialColumns (ROWID) Colunas de identificadores de linha únicos. Encontre as melhores colunas para identificar linhas específicas.
rowVerColumns() SQLSpecialColumns (ROWVER) Colunas de versão por linha. Implemente concorrência otimista (detecte modificações simultâneas).
getTypeInfo() SQLGetTypeInfo Informações sobre tipos de dados. Descubra tipos suportados para compatibilidade multiplataforma.

Cada método retorna um cursor que você pode iterar para acessar os resultados.

Tables

Tabelas de listas e visualizações no banco de dados:

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)

parâmetros tables()

Os seguintes parâmetros controlam a descoberta da tabela:

Parâmetro Descrição
table Padrão de nome de tabela (aceita os caracteres curinga % e _).
catalog Nome do catálogo (banco de dados).
schema Padrão de nome do esquema.
tableType Filtrar por tipo: TABLE, VIEW, SYSTEM TABLE, GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, , SYNONYM.

colunas do resultado de tables()

O tables() método retorna as seguintes colunas para cada tabela ou visualização:

Coluna Descrição
table_cat Nome do catálogo (banco de dados).
table_schem Nome do esquema.
table_name Nome da tabela ou exibição.
table_type TABLE, VIEW, SYSTEM TABLE, GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, , . SYNONYM
remarks Descrição ou comentários.

Verifique se existe uma tabela

Verifique se existe uma tabela antes de consultá-la:

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

Columns

Obter informações das colunas de tabelas:

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

Parâmetros column()

Filtros para refinar a localização de colunas:

Parâmetro Descrição
table Padrão de nome da tabela.
catalog Nome do catálogo (banco de dados).
schema Padrão de nome do esquema.
column Padrão de nomes de coluna.

columns() colunas de resultado

O columns() método retorna informações detalhadas sobre cada coluna:

Coluna Descrição
table_cat, table_schem, table_name Identificadores de localização.
column_name Nome da coluna.
data_type código do tipo de dados SQL
type_name Nome do tipo de dado (por exemplo, varchar, int).
column_size Comprimento máximo ou precisão.
buffer_length Tamanho do buffer para transferências.
decimal_digits Escala para tipos numéricos.
nullable 0 para NOT NULL, 1 para anulável.
column_def Valor padrão.
ordinal_position Posição da coluna (baseada em 1).
is_nullable "YES" ou "NO".

Procedimentos armazenados

Conheça os procedimentos armazenados:

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

parâmetros de procedures()

Filtre procedimentos armazenados por nome ou esquema:

Parâmetro Descrição
procedure Padrão de nome do procedimento.
catalog Nome do catálogo (banco de dados).
schema Padrão de nome do esquema.

colunas de resultado de procedures()

O procedures() método retorna metadados para cada procedimento armazenado:

Coluna Descrição
procedure_cat, procedure_schem Identificadores de localização.
procedure_name Nome do procedimento.
num_input_params Número de parâmetros de entrada.
num_output_params Número de parâmetros de saída.
num_result_sets Número de conjuntos de resultados.
remarks Description.
procedure_type Indicador de tipo.

Chaves primárias

Obtenha as colunas de chave primária de uma tabela:

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

parâmetros primaryKeys()

Parâmetros para recuperar informações de chave primária:

Parâmetro Descrição
table Nome da tabela (obrigatório).
catalog Nome do catálogo (banco de dados).
schema Nome do esquema.

Colunas de resultados primaryKeys()

O primaryKeys() método retorna as seguintes informações:

Coluna Descrição
table_cat, table_schem, table_name Identificadores de localização.
column_name Coluna na chave primária.
key_seq Posição na chave de múltiplas colunas (baseada em 1).
pk_name Nome da restrição de chave primária.

Chaves estrangeiras

Descubra relacionamentos de chave estrangeira:

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

parâmetros foreignKeys()

Especifique tabelas de chave primária ou estrangeira para descobrir relacionamentos:

Parâmetro Descrição
table Nome da tabela de chave primária.
catalog Catálogo de chaves primárias.
schema Esquema de chave primária.
foreignTable Nome da tabela de chave estrangeira.
foreignCatalog Catálogo de chaves estrangeiras.
foreignSchema Esquema de chave estrangeira.

Colunas de resultados foreignKeys()

O foreignKeys() método retorna as seguintes colunas descrevendo relacionamentos:

Coluna Descrição
pktable_cat, pktable_schem, pktable_name Tabela referenciada (primária).
pkcolumn_name Coluna referenciada.
fktable_cat, fktable_schem, fktable_name Tabela de referência (estrangeira).
fkcolumn_name Referenciando coluna.
key_seq Posição na chave multicoluna.
update_rule Ação em UPDATE.
delete_rule Ação em DELETE.
fk_name Nome da restrição de chave estrangeira.
pk_name Nome da restrição de chave primária.

Índices e estatísticas

Obter informações sobre índices de uma tabela:

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

parâmetros de statistics()

Configure a descoberta de índice com estes filtros:

Parâmetro Default Descrição
table (obrigatório) Nome da tabela.
catalog None Nome do catálogo (banco de dados).
schema None Nome do esquema.
unique Falso Apenas retorne índices únicos.
quick Verdade Evite a obtenção dispendiosa de cardinalidade e páginas.

Colunas de resultado de statistics()

O statistics() método retorna informações de índice e estatísticas:

Coluna Descrição
table_cat, table_schem, table_name Identificadores de localização.
non_unique 0 para único, 1 para não único.
index_name Nome do índice.
type Tipo de índice.
ordinal_position Posição da coluna no índice.
column_name Nome da coluna.
asc_or_desc A para subir, D para descer.
cardinality Estimativa do número de linhas.
pages Contagem de páginas.

Colunas de identificadores de linha

Encontre colunas que identifiquem uma linha de forma única:

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

Esse método retorna o melhor conjunto de colunas para identificar unicamente uma linha, que pode ser a chave primária ou um índice único.

Colunas de versão da linha

Encontre colunas que sejam atualizadas automaticamente quando qualquer valor de linha muda. Use colunas de versão de linha para controle otimista de concorrência, onde você lê a versão de uma linha, faz alterações e depois verifica se a versão atual da linha é a mesma antes de escrever:

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

O resultado normalmente inclui rowversion/timestamp colunas usadas para concorrência otimista.

Informações de tipo de dados

Obtenha informações sobre tipos de dados SQL suportados:

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

parâmetros getTypeInfo()

Parâmetros opcionais para filtrar os tipos de SQL suportados:

Parâmetro Descrição
sqlType Constante de tipo SQL (omita para todos os tipos).

Considerações de segurança

Cuidado

Esses métodos expõem metadados do esquema do banco de dados. Embora os próprios métodos sejam seguros para executar, as informações retornadas revelam a estrutura do seu banco de dados (nomes de tabelas, nomes de colunas, relacionamentos, tipos de dados).

  • Não exponha metadados brutos a usuários não confiáveis.
  • Sanitizar ou filtrar resultados em aplicações multilocatárias.
  • Restringa o acesso em aplicações voltadas para o exterior.

Exemplo: Gerar um relatório de esquema

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