Logo da Disciplina IFSC Florianópolis

GE2014902 - Geoprocessamento 2

Versão 2026.1

← Sumário · ← Cap. anterior: CONSTRUÇÃO DE BANCO DE DADOS ESPACIAIS

Capítulo 8: Atividade Prática Supervisionada

Balneabilidade no PostGIS

Objetivo da Atividade

Atuar como Analista GIS organizando dados de balneabilidade de Florianópolis e integrando-os com a demografia local via SQL Espacial.

O trabalho será individual e realizado inteiramente no banco de dados PostgreSQL/PostGIS, a partir de dados oficiais.

Cada estudante será responsável por limpar, padronizar e analisar medições de balneabilidade cruzando-as com a densidade demográfica setorial (Geoportal — Censo IBGE 2022), garantindo consistência entre atributos e geometrias.

1. Contexto do Projeto

O banco de dados espacial PostgreSQL/PostGIS é a ferramenta central desta atividade. Você trabalhará a partir de dados oficiais "brutos" (raw), realizando todo o ciclo de inteligência geográfica: extração, tratamento, análise e cruzamento de informações.

O trabalho é individual e deve ser realizado estritamente dentro do seu Schema pessoal.

2. Organização dos Dados

No servidor, você encontrará um schema público (somente leitura) contendo as seguintes tabelas de origem:

  • public.pontos_coleta_raw — Pontos geográficos de coleta
  • public.balneabilidade_2024_raw — Planilha de medições (sem geometria)
  • public.densidade_demografica_raw — Polígonos censitários

Importante: Você não deve alterar nada em public.*. Sempre copie os dados para o seu schema bal_seunome usando CREATE TABLE AS antes de higienizar ou editar. Suas tabelas de trabalho devem seguir nomes claros como pontos_coleta, densidade_demografica e relatorio_balneabilidade.

Etapa 0: Preparação do Ambiente

Antes de manipular dados, precisamos garantir que sua "mesa de trabalho" (Schema) esteja pronta. No QGIS DB Manager, execute um bloco por vez para evitar travamentos.

Requisitos:

  1. Crie seu schema pessoal no banco seguindo o padrão: bal_seunome.
  2. Verifique suas permissões de escrita criando e apagando uma tabela de teste.

Roteiro de Comandos SQL

Passo 1: Criar o seu espaço de trabalho (Schema)

-- Substitua 'seunome' pelo seu usuário real. Ex: bal_joao
CREATE SCHEMA bal_seunome;

Passo 2: Testar permissão de escrita (Criar tabela temporária)

-- Tente criar uma tabela simples para ver se funciona
CREATE TABLE bal_seunome.teste_permissao (
    id INTEGER,
    nome VARCHAR(50)
);

Passo 3: Limpeza (Apagar tabela de teste)

-- Se o passo anterior funcionou, remova a tabela de teste
DROP TABLE bal_seunome.teste_permissao;

Etapa 1: Criação de Tabelas de Trabalho

Teoria: Independência dos Dados

Vamos utilizar a técnica Snapshot (Cópia Estática). Ao contrário de uma View, que é uma janela dinâmica para o dado original, o comando CREATE TABLE AS cria uma cópia física independente.

Conceitos Fundamentais

  • Snapshot (Fotografia): Ao criar uma tabela (ex: florianopolis_bairros) a partir da original (ex: sc_bairros), você registra os dados daquele exato momento. Futuras atualizações na tabela de Santa Catarina não afetam a sua. O vínculo dinâmico deixa de existir.
  • Independência: Com a tabela exclusiva no seu schema, é possível editar geometrias, adicionar ou remover atributos e ajustar campos conforme necessário (algo impossível numa view de leitura).
  • Desempenho: Consultar apenas dados de Florianópolis torna o processamento espacial drasticamente mais rápido do que filtrar toda a tabela estadual a cada movimento do mapa.

Convenção de Nomes (snake_case)

Para evitar problemas com aspas e compatibilidade, adote sempre o padrão snake_case (letras minúsculas, sem acentos, separadas por underline) para schemas, tabelas e colunas.

Exemplos: florianopolis_demografia, relatorio_balneabilidade, pontos_coleta, codigo_setor, nome_ponto.

Prática: A Lógica SQL

A estrutura lógica abaixo é um modelo que deve ser adaptado à estrutura real das tabelas de origem (nomes de colunas, filtros, etc.). Confira sempre os nomes exatos no DB Manager antes de rodar.

CREATE TABLE bal_seunome.pontos_balneabilidade AS
SELECT
    coluna_tx_BAIRRO_2020        AS id_ponto,  -- Nome original não padronizado; renomeado para 'id_ponto' em snake_case, seguindo o padrão do banco
    "BAIRRO_TEXTO_RUIM_ORIGINAL" AS bairro,    -- Nome original pouco legível; renomeado para 'bairro' em snake_case para facilitar leitura e consultas
    geom                                      -- Coluna de geometria mantida; 'geom' é o nome padrão adotado para a geometria
FROM
    public.tabela_gigante_origem
WHERE
    municipio ILIKE 'Florianópolis';          -- Filtro textual com ILIKE para considerar variações de maiúsculas/minúsculas;
                                              -- ATENÇÃO: se a coluna foi criada como "MUNICIPIO" (com aspas e em MAIÚSCULAS),
                                              -- será necessário escrever "MUNICIPIO" em vez de municipio neste WHERE.

Conceito: Nomes de Colunas vs. Valores

  • Nomes de Colunas: No PostgreSQL, municipio (sem aspas) é armazenado em minúsculas. Já "MUNICIPIO" (com aspas) preserva maiúsculas e exigirá aspas para sempre nas consultas.
  • Valores de Texto: O conteúdo da célula (ex: 'Florianópolis') pode variar (FLORIANOPOLIS, Florianopolis, etc.). O filtro WHERE atua sobre o valor, não sobre o nome da coluna.

Dica Prática: Antes de filtrar, execute SELECT DISTINCT municipio FROM public.tabela_gigante_origem; para identificar todas as variações de escrita (maiúsculas, sem acento, espaços extras) e decidir se usará apenas ILIKE ou funções de limpeza.

Engenharia de Prompt (Uso de IA)

Use os modelos abaixo para gerar suas queries na IA. Não esqueça de mencionar para a IA criar no schema bal_seunome.

Dica de Prompt: Tabela Demografia

"Aja como especialista PostGIS. Tenho uma tabela de origem chamada [NOME_DA_RAW_AQUI].

Gere o SQL para criar a tabela florianopolis_demografia no meu schema (use o placeholder bal_seunome).
Requisitos:
1. Filtre onde 'nm_mun' é Florianópolis.
2. Selecione: 'cd_setor' (como codigo_setor), 'nm_bairro' (como bairro), 'v0001...' (como populacao) e a 'geom'.
3. Use CREATE TABLE AS SELECT."

O "Pulo do Gato": PK e Índices

Tabelas criadas assim nascem "mortas" para edição no QGIS (sem Chave Primária, o QGIS não permite salvar edições) e lentas (sem Índice Espacial, o desempenho de pan/zoom e joins degrada rapidamente).

Execute os passos abaixo separadamente para cada tabela criada:

Passo 1Adicionar Chave Primária (PK)

ALTER TABLE bal_seunome.sua_tabela ADD COLUMN id SERIAL PRIMARY KEY;

Passo 2Adicionar Índice Espacial

CREATE INDEX idx_nome_geom ON bal_seunome.sua_tabela USING GIST (geom);

* Repita esses dois passos para a tabela de demografia, pontos e histórico (na de histórico, pule o índice espacial pois ela não tem mapa).

Etapa 2: Higienização de Dados

Dados importados de planilhas frequentemente chegam como TEXTO. Antes de alterar a tabela, inspecione os valores com um SELECT DISTINCT e teste suas expressões de limpeza (ex: SELECT REPLACE(temperatura, ',', '.')::NUMERIC FROM ... LIMIT 20).

2.1 Conversão de Tipos (Casting)

Exemplo 1: Convertendo Data (De Texto 'DD/MM/YYYY' para DATE)

ALTER TABLE bal_seunome.relatorio_balneabilidade 
ALTER COLUMN data_coleta TYPE DATE 
USING TO_DATE(data_coleta, 'DD/MM/YYYY');

Exemplo 2: Limpando Números (Trocando vírgula por ponto)

-- Necessário para cálculos de estatística
ALTER TABLE bal_seunome.relatorio_balneabilidade 
ALTER COLUMN temperatura TYPE NUMERIC 
USING REPLACE(temperatura, ',', '.')::NUMERIC;

Exemplo 3: Removendo símbolos (Ex: '< 10' vira 10)

-- Limpeza da coluna de bactérias
UPDATE bal_seunome.relatorio_balneabilidade 
SET ecoli = REGEXP_REPLACE(ecoli, '[^0-9]', '', 'g')::INTEGER;

2.2 Padronização de SRID (Sistema de Coordenadas)

Para realizar cruzamentos espaciais, as tabelas de mapa devem "falar a mesma língua" métrica (UTM 22S - SIRGAS 2000).

Passo 1: Verificar o SRID atual

SELECT ST_SRID(geom) FROM bal_seunome.densidade_demografica LIMIT 1;

Passo 2: Transformar para UTM 22S (Metros)

ALTER TABLE bal_seunome.densidade_demografica 
ALTER COLUMN geom TYPE geometry(MultiPolygon, 31982) 
USING ST_Transform(geom, 31982);

Etapa 3: Join de Atributos (Table to Table)

Objetivo: Criar uma VIEW que una os dados de qualidade da água (Tabela) com a geometria (Ponto).

💡 Dica de Ouro

Use TRIM() e UPPER() para evitar que espaços extras ou diferenças de caixa (maiúscula/minúscula) quebrem o vínculo entre os nomes.

CREATE VIEW bal_seunome.vw_balneabilidade_mapa AS
SELECT
    h.data_coleta,
    h.condicao,
    h.ecoli,
    p.geom       -- Trazendo a geometria da tabela de pontos
FROM
    bal_seunome.relatorio_balneabilidade h
JOIN
    bal_seunome.pontos_coleta p
ON
    -- Higienização "on-the-fly" para garantir o vínculo
    TRIM(UPPER(h.nome_ponto)) = TRIM(UPPER(p.nome_local));

Etapa 4: Join Espacial (Spatial Join)

Objetivo: Descobrir em qual Setor Censitário cada ponto de coleta está localizado.

Requisito Crítico: SRID

Use ST_Transform para garantir que o ponto (geralmente em graus/4326) esteja em metros (31982) igual à demografia.

CREATE VIEW bal_seunome.vw_pontos_com_demografia AS
SELECT
    p.nome_local,
    d.bairro,
    d.populacao_total,
    d.densidade_ha
FROM
    bal_seunome.pontos_coleta p
JOIN
    bal_seunome.densidade_demografica d
ON
    -- A mágica espacial: Verdadeiro se o Ponto P estiver DENTRO do Polígono D
    ST_Within( ST_Transform(p.geom, 31982), d.geom );

Etapa 5: Consultas Temáticas

Agora que temos Views poderosas integrando Balneabilidade, Localização e Demografia, escolha um foco para extrair inteligência dos dados.

Foco Turístico

Liste praias que mantiveram condição "Própria" consistentemente e estão próximas a áreas densamente povoadas.

Dica: Use GROUP BY e AVG(ecoli).

Foco Fiscal

Quais micro-regiões (Setores) possuem a maior quantidade de praias "Impróprias"? Cruzamento direto entre resultado ruim e bairro.

Dica: Filtre por condição e conte por bairro.

Troubleshooting: Por que meu SQL falhou?

Checklist de sobrevivência para erros comuns no PostGIS.

1. O Erro das Aspas

Comum em dados importados de GPKG ou planilhas que criam colunas com acentos/maiúsculas. Esse comportamento obriga o uso de aspas duplas para referenciar a coluna (veja a nota conceitual na Etapa 1).

SELECT Municipio FROM ... ❌ Erro

SELECT "Município" FROM ... ✅ Certo

2. O Erro do Ponto vs Vírgula

O banco de dados fala inglês (ponto decimal). Se você tentar somar '12,5', ele falha.

Solução: Use REPLACE(coluna, ',', '.') antes do CAST.

3. O Vazio Espacial

Seu JOIN espacial rodou mas retornou 0 linhas? Verifique o SRID.

SELECT ST_SRID(geom) ...

Se um for 4326 (Graus) e o outro 31982 (Metros), eles nunca vão se cruzar. Use ST_Transform.

4. O Fantasma do Espaço em Branco

'Canasvieiras' é diferente de 'Canasvieiras ' (com espaço no final).

Solução: Sempre use TRIM() ao fazer joins de texto.

Fim da Atividade Prática

Gere seus mapas no QGIS conectando-se às Views criadas.