Dia 10 — SQL: inserir e consultar: PHP e MySQL

Informatica · Conteudo · publicado em 02/10/2026
Dia 10 de 17

SQL: inserir e consultar

Aula 1

INSERT

Inserir uma linha

INSERT INTO grava uma linha. O nome da tabela vem depois de INTO e os valores

na mesma ordem das colunas listadas; coluna omitida recebe NULL ou o DEFAULT

que a tabela define. String de texto vai entre aspas simples — '' é vazio,

NULL é ausência de valor, e são coisas diferentes.

A forma mais segura: nomear as colunas

INSERT INTO <tabela> (<coluna>, <coluna>, ...) VALUES (<valor>, <valor>, ...);

Nomear as colunas protege do dia em que alguém acrescentar uma coluna nova à

tabela: a instrução continua funcionando, enquanto `INSERT INTO tabela VALUES

(...)` quebra quando a tabela cresce.

Inserir várias linhas de uma vez

Um INSERT aceita várias tuplas separadas por vírgula, e o banco continua o

AUTO_INCREMENT sem repetir número entre elas. A diferença aparece quando são

milhares de linhas: uma instrução só, em vez de uma por linha.

A mesma forma, com a lista de valores

INSERT INTO <tabela> (<colunas>)
VALUES (<valores>), (<valores>), (<valores>);

Copiar de uma tabela para outra

INSERT ... SELECT lê de uma tabela e grava em outra sem passar pelos valores.

Nele, SELECT vem no lugar de VALUES, e as colunas do SELECT devem

corresponder às colunas do destino.

A forma da cópia

INSERT INTO <tabela_destino> (<colunas>)
SELECT <colunas> FROM <tabela_origem> WHERE <condicao>;

Se uma coluna obrigatória ficar sem valor, o INSERT é recusado: o erro vem com o

número da linha que falhou, o que dá para corrigir e tentar de novo.

Exemplo

<?php
declare(strict_types=1);

// As tres formas de INSERT: uma linha, varias linhas e copia de outra tabela.
// Nao ha conexao: o script imprime o SQL que o aluno executa no cliente.

$sql = <<<'SQL'
-- 1) uma linha, com as colunas nomeadas (a forma segura)
INSERT INTO cursos (nome, carga_horaria, valor)
VALUES ('Banco de dados', 80, 1450.00);

-- 2) varias linhas de uma vez: o AUTO_INCREMENT nao se repete entre elas
INSERT INTO cursos (nome, carga_horaria, valor) VALUES
  ('Banco de dados',         80, 1450.00),
  ('Programacao PHP',        60, 1200.00),
  ('Seguranca da informacao',40,  980.50),
  ('Redes e infraestrutura', 50, 1100.00);

-- 3) o que o banco faz sozinho quando a coluna e omitida
INSERT INTO cursos (nome, carga_horaria, valor)
VALUES ('Banco de dados', 80, 1450.00), ('Programacao PHP', 60, 1200.00);

-- 4) INSERT SELECT: copia linhas de uma tabela para outra
INSERT INTO cursos_desativados (nome, carga_horaria, valor)
SELECT nome, carga_horaria, valor
FROM cursos
WHERE ativo = 0;

-- conferir o resultado
SELECT id, nome, carga_horaria, valor FROM cursos ORDER BY id;
SQL;

echo $sql . "\n";

Saída real

-- 1) uma linha, com as colunas nomeadas (a forma segura)
INSERT INTO cursos (nome, carga_horaria, valor)
VALUES ('Banco de dados', 80, 1450.00);

-- 2) varias linhas de uma vez: o AUTO_INCREMENT nao se repete entre elas
INSERT INTO cursos (nome, carga_horaria, valor) VALUES
  ('Banco de dados',         80, 1450.00),
  ('Programacao PHP',        60, 1200.00),
  ('Seguranca da informacao',40,  980.50),
  ('Redes e infraestrutura', 50, 1100.00);

-- 3) o que o banco faz sozinho quando a coluna e omitida
INSERT INTO cursos (nome, carga_horaria, valor)
VALUES ('Banco de dados', 80, 1450.00), ('Programacao PHP', 60, 1200.00);

-- 4) INSERT SELECT: copia linhas de uma tabela para outra
INSERT INTO cursos_desativados (nome, carga_horaria, valor)
SELECT nome, carga_horaria, valor
FROM cursos
WHERE ativo = 0;

-- conferir o resultado
SELECT id, nome, carga_horaria, valor FROM cursos ORDER BY id;
Aula 2

SELECT básico e WHERE

A forma do SELECT

SELECT escolhe as colunas, FROM diz de onde elas vêm. A ordem de leitura da

frase é o contrário: o SQL se escreve de fora para dentro, começando pelo que se

quer ver. O asterisco traz todas as colunas — prático no começo, ruim em código

que vai para produção, porque uma coluna nova aparece sozinha na tela.

A consulta mínima e a ordem das cláusulas

SELECT <coluna>, <coluna> FROM <tabela>;
SELECT * FROM <tabela>;

A ordem das cláusulas é fixa: SELECT, FROM, WHERE, GROUP BY, HAVING,

ORDER BY, LIMIT. O erro mais comum é tentar colocar o WHERE antes do

FROM, e a resposta é sempre a mesma mensagem do servidor.

Filtrar com WHERE

WHERE fica depois do FROM e vale para a linha, não para a coluna. Ele combina

condições com AND, OR e NOT, e compara com =, <>, >, <, >= e <=.

Texto com acento compara exatamente como foi gravado: WHERE cidade = 'Sao Paulo'

não acha São Paulo.

Os três operadores lógicos e a precedência

SELECT <colunas> FROM <tabela>
WHERE <condicao> AND <condicao>;

SELECT <colunas> FROM <tabela>
WHERE (<condicao> OR <condicao>) AND <condicao>;

AND tem precedência sobre OR: WHERE a = 1 OR b = 2 AND c = 3 é lido como

a = 1 OR (b = 2 AND c = 3). Quando a intenção era o outro sentido, os

parênteses resolvem — e essa é a forma mais segura de escrever.

Maneira de escreverO que faz
<> ou !=Diferente de
BETWEEN a AND bDentro da faixa, com as bordas
IN (a, b, c)Igual a um dos valores da lista
LIKE 'texto%'Começa com o texto
IS NULLA coluna não tem valor

Exemplo

<?php
declare(strict_types=1);

// SELECT com WHERE: a ordem das clausulas e fixa e a combinacao de
// condicoes e o que mais gera consulta errada.

$sql = <<<'SQL'
-- a forma minima: colunas e tabela
SELECT id, nome, email FROM alunos;

-- asterisco traz tudo: pratico no teste, perigoso em codigo de producao
SELECT * FROM alunos;

-- igualdade e os comparadores
SELECT nome, cidade FROM alunos WHERE cidade = 'Sao Paulo';
SELECT nome FROM alunos WHERE idade >= 18 AND situacao = 'regular';

-- AND tem precedencia sobre OR; os parenteses dizem qual era a intencao
SELECT nome FROM alunos
WHERE (cidade = 'Sao Paulo' OR cidade = 'Campinas') AND ativo = 1;

-- NOT nega a condicao
SELECT nome FROM alunos WHERE NOT ativo = 1;

-- varias condicoes com OR viram um IN mais legivel
SELECT nome FROM cursos
WHERE nome = 'Banco de dados' OR nome = 'Programacao PHP' OR nome = 'Redes';

-- o operador IN substitui a cadeia de OR e o NOT IN nega a lista
SELECT nome FROM cursos
WHERE nome IN ('Banco de dados', 'Programacao PHP', 'Redes');

-- IS NULL e o jeito correto de procurar coluna sem valor
SELECT id, nome FROM alunos WHERE cidade IS NULL;
SQL;

echo $sql . "\n";

Saída real

-- a forma minima: colunas e tabela
SELECT id, nome, email FROM alunos;

-- asterisco traz tudo: pratico no teste, perigoso em codigo de producao
SELECT * FROM alunos;

-- igualdade e os comparadores
SELECT nome, cidade FROM alunos WHERE cidade = 'Sao Paulo';
SELECT nome FROM alunos WHERE idade >= 18 AND situacao = 'regular';

-- AND tem precedencia sobre OR; os parenteses dizem qual era a intencao
SELECT nome FROM alunos
WHERE (cidade = 'Sao Paulo' OR cidade = 'Campinas') AND ativo = 1;

-- NOT nega a condicao
SELECT nome FROM alunos WHERE NOT ativo = 1;

-- varias condicoes com OR viram um IN mais legivel
SELECT nome FROM cursos
WHERE nome = 'Banco de dados' OR nome = 'Programacao PHP' OR nome = 'Redes';

-- o operador IN substitui a cadeia de OR e o NOT IN nega a lista
SELECT nome FROM cursos
WHERE nome IN ('Banco de dados', 'Programacao PHP', 'Redes');

-- IS NULL e o jeito correto de procurar coluna sem valor
SELECT id, nome FROM alunos WHERE cidade IS NULL;
Aula 3

LIKE, IN, BETWEEN e IS NULL

LIKE

LIKE compara string com um padrão. % representa qualquer sequência de

caracteres, inclusive vazia, e _ representa exatamente um caractere. O padrão

costuma vir com aspas simples, mesmo sem %: WHERE nome LIKE 'Ana' é

exatamente igual a WHERE nome = 'Ana'.

A forma do padrão

SELECT <colunas> FROM <tabela> WHERE <coluna> LIKE '<padrao>%';
PadrãoO que acha
'Mar%'Começa com Mar
'%Silva'Termina com Silva
'%ar%'Tem ar no meio
'Programacao_php'Exatamente um caractere no lugar do _

LIKE não usa índice, exceto no começo do padrão com VARCHAR. Se a busca for

por email ou por nome exato, = é mais rápido que LIKE '%termo%'.

IN, BETWEEN e IS NULL

IN testa se o valor está em uma lista e vale mais que uma cadeia de OR.

BETWEEN testa faixa, com as duas bordas incluídas. IS NULL verifica ausência

de valor, e é o único jeito correto de fazer isso: = NULL nunca devolve linha,

porque NULL = NULL é desconhecido para o SQL.

As três formas de filtro de conjunto

SELECT <colunas> FROM <tabela> WHERE <coluna> IN (<valor>, <valor>);
SELECT <colunas> FROM <tabela> WHERE <coluna> BETWEEN <inicio> AND <fim>;
SELECT <colunas> FROM <tabela> WHERE <coluna> IS [NOT] NULL;
BuscaFiltro
Um dos valores da listaIN (...) e NOT IN (...)
Dentro de uma faixaBETWEEN a AND b
Coluna sem valorIS NULL
Coluna preenchidaIS NOT NULL
Padrão de textoLIKE, com % e _

Exemplo

<?php
declare(strict_types=1);

// Os quatro filtros de conjunto: padrao de texto, lista, faixa e vazio.
// Todos entram depois do FROM e antes do ORDER BY.

$sql = <<<'SQL'
-- LIKE: % e qualquer sequencia, _ e exatamente um caractere
SELECT id, nome FROM alunos WHERE nome LIKE 'Mar%';
SELECT id, nome FROM alunos WHERE nome LIKE '%Silva';
SELECT id, nome FROM alunos WHERE nome LIKE '%ar%';
SELECT id, nome FROM cursos WHERE nome LIKE 'Programacao_php';

-- NOT LIKE nega o padrao
SELECT id, nome FROM alunos WHERE nome NOT LIKE 'Mar%';

-- IN: igual a um dos valores da lista
SELECT id, nome FROM cursos
WHERE nome IN ('Banco de dados', 'Programacao PHP', 'Redes e infraestrutura');

-- NOT IN: exclui os valores da lista
SELECT id, nome FROM cursos
WHERE nome NOT IN ('Banco de dados', 'Programacao PHP');

-- BETWEEN: faixa com as duas bordas incluidas
SELECT id, nome, valor FROM cursos WHERE valor BETWEEN 900.00 AND 1300.00;
SELECT id, nome FROM alunos WHERE nascimento BETWEEN '2000-01-01' AND '2004-12-31';

-- IS NULL e IS NOT NULL: coluna sem valor e coluna preenchida
SELECT id, nome FROM alunos WHERE cidade IS NULL;
SELECT id, nome, cidade FROM alunos WHERE cidade IS NOT NULL;

-- a ordem das clausulas nao muda: SELECT, FROM, WHERE
SELECT id, nome, cidade
FROM alunos
WHERE cidade IN ('Sao Paulo', 'Campinas') AND nome LIKE 'A%'
ORDER BY nome;
SQL;

echo $sql . "\n";

Saída real

-- LIKE: % e qualquer sequencia, _ e exatamente um caractere
SELECT id, nome FROM alunos WHERE nome LIKE 'Mar%';
SELECT id, nome FROM alunos WHERE nome LIKE '%Silva';
SELECT id, nome FROM alunos WHERE nome LIKE '%ar%';
SELECT id, nome FROM cursos WHERE nome LIKE 'Programacao_php';

-- NOT LIKE nega o padrao
SELECT id, nome FROM alunos WHERE nome NOT LIKE 'Mar%';

-- IN: igual a um dos valores da lista
SELECT id, nome FROM cursos
WHERE nome IN ('Banco de dados', 'Programacao PHP', 'Redes e infraestrutura');

-- NOT IN: exclui os valores da lista
SELECT id, nome FROM cursos
WHERE nome NOT IN ('Banco de dados', 'Programacao PHP');

-- BETWEEN: faixa com as duas bordas incluidas
SELECT id, nome, valor FROM cursos WHERE valor BETWEEN 900.00 AND 1300.00;
SELECT id, nome FROM alunos WHERE nascimento BETWEEN '2000-01-01' AND '2004-12-31';

-- IS NULL e IS NOT NULL: coluna sem valor e coluna preenchida
SELECT id, nome FROM alunos WHERE cidade IS NULL;
SELECT id, nome, cidade FROM alunos WHERE cidade IS NOT NULL;

-- a ordem das clausulas nao muda: SELECT, FROM, WHERE
SELECT id, nome, cidade
FROM alunos
WHERE cidade IN ('Sao Paulo', 'Campinas') AND nome LIKE 'A%'
ORDER BY nome;
Aula 4

ORDER BY, LIMIT e paginação

ORDER BY

ORDER BY vem depois do WHERE e ordena o resultado pela coluna indicada, sem

alterar os dados guardados. Sem ASC ou DESC a ordenação é crescente. Números

ordenam por valor, texto ordena por ordem de alfabeto e NULL fica no começo em

ASC.

Uma ou várias colunas

SELECT <colunas> FROM <tabela> ORDER BY <coluna> [ASC|DESC], <coluna> [ASC|DESC];

Cada coluna tem sua própria direção, e a ordenação segue a ordem em que foram

escritas: primeiro por cidade, e dentro de uma mesma cidade, por nome

decrescente.

LIMIT e OFFSET

LIMIT corta o resultado depois de ordenado — nunca antes. O LIMIT sem

ORDER BY devolve linhas em ordem arbitrária, e a página 1 e a página 2 podem

mostrar exatamente o mesmo conjunto.

O par que faz a paginação

SELECT <colunas> FROM <tabela> ORDER BY <coluna> LIMIT <quantidade> OFFSET <quantidade>;
CláusulaO que faz
LIMIT 10Devolve no máximo 10 linhas
LIMIT 10, 20Salta 10 e devolve 20 — igual a LIMIT 20 OFFSET 10
LIMIT 20 OFFSET 40Página 3, com 20 linhas por página
ORDER BYObrigatório antes do LIMIT em paginação

A partir da segunda página o OFFSET começa a custar: o banco lê e descarta as

linhas anteriores. Em tabela grande, o padrão passa a ser buscar por chave —

WHERE id > 60 ORDER BY id LIMIT 20 — que não pula nada.

Exemplo

<?php
declare(strict_types=1);

// ORDER BY, LIMIT e paginacao. A ordenacao vem antes do corte: sem ela,
// LIMIT devolve linhas em ordem arbitraria e a pagina se repete.

$sql = <<<'SQL'
-- ordenacao crescente (padrao) e decrescente
SELECT id, nome, valor FROM cursos ORDER BY valor ASC;
SELECT id, nome, valor FROM cursos ORDER BY valor DESC;

-- varias colunas, cada uma com sua direcao
SELECT nome, cidade FROM alunos
ORDER BY cidade ASC, nome DESC;

-- texto ordena por alfabeto, numero por valor, NULL fica no comeco em ASC
SELECT id, nome, cidade FROM alunos ORDER BY cidade;

-- LIMIT corta o resultado
SELECT id, nome FROM cursos ORDER BY nome LIMIT 2;

-- as duas formas de pedir 20 linhas pulando as 40 primeiras (pagina 3)
SELECT id, nome FROM alunos ORDER BY nome LIMIT 20 OFFSET 40;
SELECT id, nome FROM alunos ORDER BY nome LIMIT 40, 20;

-- a pagina anterior e a seguinte, com a mesma ordenacao
SELECT id, nome FROM alunos ORDER BY nome LIMIT 20 OFFSET 0;
SELECT id, nome FROM alunos ORDER BY nome LIMIT 20 OFFSET 20;

-- contagem total, para o rodape saber quantas paginas existem
SELECT COUNT(*) AS total FROM alunos;
SQL;

echo $sql . "\n";

Saída real

-- ordenacao crescente (padrao) e decrescente
SELECT id, nome, valor FROM cursos ORDER BY valor ASC;
SELECT id, nome, valor FROM cursos ORDER BY valor DESC;

-- varias colunas, cada uma com sua direcao
SELECT nome, cidade FROM alunos
ORDER BY cidade ASC, nome DESC;

-- texto ordena por alfabeto, numero por valor, NULL fica no comeco em ASC
SELECT id, nome, cidade FROM alunos ORDER BY cidade;

-- LIMIT corta o resultado
SELECT id, nome FROM cursos ORDER BY nome LIMIT 2;

-- as duas formas de pedir 20 linhas pulando as 40 primeiras (pagina 3)
SELECT id, nome FROM alunos ORDER BY nome LIMIT 20 OFFSET 40;
SELECT id, nome FROM alunos ORDER BY nome LIMIT 40, 20;

-- a pagina anterior e a seguinte, com a mesma ordenacao
SELECT id, nome FROM alunos ORDER BY nome LIMIT 20 OFFSET 0;
SELECT id, nome FROM alunos ORDER BY nome LIMIT 20 OFFSET 20;

-- contagem total, para o rodape saber quantas paginas existem
SELECT COUNT(*) AS total FROM alunos;