🏗️ CAPÍTULO 11: ECOSSISTEMA SQL E DDL


🎯 Objetivos de Aprendizagem

Ao final deste capítulo (estimativa: 2 horas de estudo autoguiado), você será capaz de:

  • 🔹 Compreender as 5 famílias de comandos SQL: DDL (Definição), DML (Manipulação), DQL (Consulta), DCL (Controle) e TCL (Transação).
  • 🔹 Dominar a criação e gestão de Schemas (Namespaces) e tabelas com CREATE TABLE, ALTER TABLE e DROP TABLE.
  • 🔹 Diferenciar a execução declarativa do SQL (otimizador de consultas) da programação procedural tradicional.
  • 🔹 Implementar inspeção e criação programática de schemas (metadados) com SQLAlchemy 2.0. (Migrações versionadas com Alembic são o foco do Capítulo 17.)

A primeira ideia que define um desenvolvedor experiente é entender que a SQL (Structured Query Language) não é apenas uma ferramenta, mas uma linguagem declarativa de escala global, capaz de gerenciar desde pequenos aplicativos até a bolsa de valores. 🛡️🧩

🏢 O Cenário Prático (Seu Desafio)

A TecProExpress decidiu criar um módulo de "Agenda de Contatos" para os fornecedores logísticos. Os analistas desenharam o MER, mas o banco de dados ainda está vazio.

"Seu desafio é abrir o terminal (ou a interface DBeaver/pgAdmin) e usar a linguagem SQL para construir as fundações do prédio: criar o espaço de trabalho (Schema) e a tabela que armazenará os fornecedores, com regras rígidas."


🧠 Fundamentos: As 5 Famílias da SQL

A SQL é dividida em 5 subconjuntos. Todo o nosso trabalho até agora na criação de tabelas pertenceu ao primeiro grupo.

SiglaSignificadoComandos PrincipaisO que faz?
DDLData Definition LanguageCREATE, ALTER, DROPMonta o "esqueleto" do banco.
DMLData Manipulation LanguageINSERT, UPDATE, DELETEManipula os "órgãos" (dados).
DQLData Query LanguageSELECTFaz as consultas e relatórios.
DCLData Control LanguageGRANT, REVOKESegurança (Dá e tira permissão).
TCLTransaction Control LanguageCOMMIT, ROLLBACKSalva ou Cancela um lote de ações.

📊 Fluxo de Processamento Declarativo

Diferente do Java ou Python (onde você diz como fazer o laço de repetição), a SQL é Declarativa. Você diz o que quer, e o SGBD se vira para otimizar.

flowchart LR
    A["📜 Declaração SQL"] --> B{"⚙️ Otimizador SGBD"}
    B -- "Calcula a Rota" --> C["🗺️ Plano de Execução"]
    C --> D["📊 Resultado Final"]

📖 Exemplo Guiado: O DDL em Ação (Criando a Base)

Sempre organize seus projetos criando um SCHEMA. Ele funciona como uma "pasta" dentro do banco de dados, evitando que as tabelas da logística se misturem com as do RH.

🛠️ Código do Exemplo

-- PASSO 1: DDL (Criação do Namespace/Schema)
CREATE SCHEMA logistica;

-- PASSO 2: DDL (Criação da Tabela com Constraints Base)
CREATE TABLE logistica.fornecedor (
    id INT PRIMARY KEY,
    nome_fantasia VARCHAR(100) NOT NULL,
    cnpj CHAR(14) UNIQUE
);

-- PASSO 3: DDL (Evoluindo a tabela - ALTER)
ALTER TABLE logistica.fornecedor ADD COLUMN email VARCHAR(100);

-- PASSO 4: DML (Carga Inicial)
INSERT INTO logistica.fornecedor (id, nome_fantasia, cnpj, email) 
VALUES (1, 'Baterias Moura', '12345678901234', 'contato@moura.com');

🔍 Detalhamento do Código:

  • CREATE SCHEMA logistica;: Cria a área de trabalho. No Postgres, isso cria uma divisão lógica no mesmo banco. (Nota: No MySQL, Schema e Database são sinônimos).
  • logistica.fornecedor: Boa prática! Sempre referenciamos a tabela pelo nome do schema seguido de um ponto.
  • ALTER TABLE ... ADD COLUMN: A vida real muda! O comando ALTER permite colocar uma nova coluna (email) sem ter que apagar (DROP) a tabela e perder os dados.

🛠️ Prática Obrigatória: Construção e Destruição

Cenário: A base de teste para a equipe de desenvolvimento.

  1. Crie um schema chamado treinamento.
  2. Crie a tabela teste_dev dentro dele.
  3. Insira 1 linha de dados.
  4. Destrua a tabela completamente usando o comando de aniquilação do DDL.

🚀 Script de Seed (Gabarito de Ciclo de Vida)

-- 1. Cria o ambiente
CREATE SCHEMA treinamento;

-- 2. Cria a estrutura (DDL)
CREATE TABLE treinamento.teste_dev (
    id INT PRIMARY KEY,
    descricao VARCHAR(50)
);

-- 3. Insere dados (DML)
INSERT INTO treinamento.teste_dev VALUES (1, 'Cobaia 01');

-- 4. Aniquila a estrutura (DDL Destrutivo)
-- CUIDADO! O DROP apaga a tabela e todos os dados dentro dela sem aviso!
DROP TABLE treinamento.teste_dev;


💻 Ponte Prática: Do SQL Manual ao SQLAlchemy 2.0 ORM

Como o ecossistema Python gerencia DDL (Criação, Alteração e Deleção de Estruturas) de forma segura e programática?

🔴 1. A Abordagem Manual (Scripts DDL Manuais e Risco de Erro)

No modelo manual, comandos CREATE TABLE e ALTER TABLE são rodados no terminal sem testes. Um erro de sintaxe pode quebrar o deploy em produção:

# ❌ ABORDAGEM COM SQL MANUAL: DDL vulnerável e sem controle de versão
cursor.execute("CREATE TABLE IF NOT EXISTS fornecedores (id INT, nome VARCHAR(100));")
# E se precisarmos adicionar uma nova coluna 'email' em produção sem perder os dados?
cursor.execute("ALTER TABLE fornecedores ADD COLUMN email VARCHAR(100);")

🟢 2. A Abordagem com SQLAlchemy 2.0 (Metadados e Schemas Declarativos)

Com o SQLAlchemy 2.0, os metadados das tabelas são objetos Python inspecionáveis. A criação e evolução de schemas é controlada por ferramentas de migração (como o Alembic):

# ✅ ABORDAGEM MODERNA: Gerenciador de Ciclo de Vida DDL com Metadados
from sqlalchemy import create_engine, String, Integer, inspect, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session

class Base(DeclarativeBase):
    pass

class FornecedorLogisticaModel(Base):
    """Representa a tabela do Schema de Logística."""
    __tablename__ = "fornecedores_logistica"

    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    nome_fantasia: Mapped[str] = mapped_column(String(100), nullable=False)
    cnpj: Mapped[str] = mapped_column(String(14), unique=True, nullable=False)
    email: Mapped[str] = mapped_column(String(100), nullable=True)

    def __repr__(self) -> str:
        return f"FornecedorLogistica(id={self.id}, nome='{self.nome_fantasia}', cnpj='{self.cnpj}')"

🛠️ Mini-Projeto 11 (BD): Gerenciador de Ciclo de Vida de Schemas DDL

Objetivo: Construir um script que inspeciona o catálogo de metadados, cria tabelas programaticamente e valida as colunas existentes no banco.

📋 Pré-requisitos e Instalação

No terminal do seu ambiente virtual (PowerShell ou Bash), instale a biblioteca necessária:

pip install sqlalchemy

💻 Código Completo e Autocontido (miniprojeto_11_ddl.py)

Crie o arquivo miniprojeto_11_ddl.py e insira o código abaixo integralmente:

"""
Mini-Projeto 11: Gerenciador de Ciclo de Vida de Schemas DDL
Curso: GTI - Banco de Dados Relacionais e Engenharia de Software
Stack: Python 3.11+ | SQLAlchemy 2.0 | SQLite
"""
import os
from sqlalchemy import create_engine, String, Integer, inspect
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session

# 1. Definição Declarativa do Schema DDL
class Base(DeclarativeBase):
    pass

class FornecedorLogisticaModel(Base):
    """Representa a tabela do Schema de Logística."""
    __tablename__ = "fornecedores_logistica"

    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    nome_fantasia: Mapped[str] = mapped_column(String(100), nullable=False)
    cnpj: Mapped[str] = mapped_column(String(14), unique=True, nullable=False)
    email: Mapped[str] = mapped_column(String(100), nullable=True)

    def __repr__(self) -> str:
        return f"FornecedorLogistica(id={self.id}, nome='{self.nome_fantasia}', cnpj='{self.cnpj}')"

# 2. Ponto de Entrada Executável
if __name__ == "__main__":
    DB_FILE = "tecpro_ddl_demo.db"

    # Reset preventivo para garantir idempotência em testes repetidos
    if os.path.exists(DB_FILE):
        os.remove(DB_FILE)

    engine = create_engine(f"sqlite:///{DB_FILE}", echo=False)

    print("🏗️ CICLO DE VIDA DDL E METADADOS - TECPROEXPRESS")
    print("=" * 65)

    # 1. DDL: Criação das Tabelas
    print("1. [DDL] Executando CREATE TABLE via Metadados...")
    Base.metadata.create_all(bind=engine)
    print("   ✅ Tabela 'fornecedores_logistica' criada com sucesso!")

    # 2. Inspecionando o Catálogo do Banco de Dados
    inspector = inspect(engine)
    colunas = inspector.get_columns("fornecedores_logistica")
    print("\n2. [METADADOS] Inspecionando colunas criadas no banco:")
    for col in colunas:
        print(f"   • Coluna: {col['name']} | Tipo: {col['type']} | Aceita Null: {col['nullable']}")

    # 3. DML: Inserindo e consultando dados
    with Session(engine) as session:
        f = FornecedorLogisticaModel(id=1, nome_fantasia="Baterias Moura S.A.", cnpj="12345678000199", email="contato@moura.com")
        session.merge(f)
        session.commit()
        print(f"\n3. [DML] Registro persistido: {f}")

    print("=" * 65)

🚀 Como Executar

Execute o script no terminal:

python miniprojeto_11_ddl.py

🖥️ Saída Esperada no Console

🏗️ CICLO DE VIDA DDL E METADADOS - TECPROEXPRESS
=================================================================
1. [DDL] Executando CREATE TABLE via Metadados...
   ✅ Tabela 'fornecedores_logistica' criada com sucesso!

2. [METADADOS] Inspecionando colunas criadas no banco:
   • Coluna: id | Tipo: INTEGER | Aceita Null: False
   • Coluna: nome_fantasia | Tipo: VARCHAR(100) | Aceita Null: False
   • Coluna: cnpj | Tipo: VARCHAR(14) | Aceita Null: False
   • Coluna: email | Tipo: VARCHAR(100) | Aceita Null: True

3. [DML] Registro persistido: FornecedorLogistica(id=1, nome='Baterias Moura S.A.', cnpj='12345678000199')
=================================================================

💡 Checkpoint de Lógica

Aviso

Dica do Arquiteto: Qual a diferença entre DELETE (DML) e DROP (DDL)? O DELETE FROM tabela apaga apenas as linhas (os dados), mas o esqueleto da tabela continua existindo para receber novos registros. O DROP TABLE é uma bomba atômica: apaga a estrutura, as colunas, as regras e, por consequência, todos os dados de uma vez. Use com extrema cautela! 🚀🛡️



🧪 Quiz de Fixação e Autoavaliação — Capítulo 11

1. Qual das alternativas lista corretamente a família SQL correspondente ao comando CREATE TABLE?

  • A) DML (Data Manipulation Language)
  • B) DDL (Data Definition Language)
  • C) DCL (Data Control Language)
  • D) TCL (Transaction Control Language)
💡 Ver Resposta e Justificativa

Resposta Correta: B
Justificativa: DDL cuida do 'esqueleto' estrutural do banco: CREATE, ALTER, DROP e TRUNCATE.


2. Qual a diferença vital entre os comandos DELETE FROM tabela; (DML) e DROP TABLE tabela; (DDL)?

  • A) DELETE apaga as linhas de dados preservando a estrutura da tabela para novos registros; DROP destrói a tabela inteira, suas colunas, regras e metadados do disco.
  • B) DELETE apaga a tabela inteira e DROP apaga apenas uma linha.
  • C) São exatamente o mesmo comando com nomes diferentes.
  • D) DROP só funciona se o computador estiver conectado à internet.
💡 Ver Resposta e Justificativa

Resposta Correta: A
Justificativa: DELETE é DML (manipula dados). DROP é DDL (destrói o objeto no catálogo).


3. No PostgreSQL, qual é a vantagem de criar múltiplos SCHEMAS (ex: logistica.pedidos, rh.funcionarios) dentro do mesmo banco de dados?

  • A) Acelerar o processador da máquina.
  • B) Criar divisões lógicas (namespaces) para organizar tabelas por módulos corporativos, evitando conflitos de nomes e permitindo permissões de acesso granulares por setor.
  • C) Economizar espaço na memória RAM.
  • D) Permitir o uso de senhas curtas.
💡 Ver Resposta e Justificativa

Resposta Correta: B
Justificativa: Schemas funcionam como 'pastas' dentro do banco de dados, mantendo módulos corporativos organizados e com permissões de acesso isoladas.


🎯 Laboratório Prático

Coloque este conhecimento em prática agora mesmo executando o roteiro autoguiado:
👉 ATIVIDADE 05: SQL DDL (ESTRUTURA)