SQL Inserindo Várias Linhas

Na aula INSERT INTO, a Ana cadastrou uma linha de cada vez. Mas um pedido da Loja Aurora quase nunca tem um item só, e quando a loja abre três seções novas, ninguém quer escrever três comandos iguais. O INSERT aceita várias linhas num comando só: basta pôr várias listas de valores depois do VALUES, separadas por vírgula. Nesta aula você vai usar isso para cadastrar categorias, clientes e um pedido completo, e vai ver uma propriedade importante: se uma das linhas tem erro, nenhuma entra.

Você vai aprender
  • A forma VALUES (…), (…), (…): várias linhas num INSERT.
  • Como o banco numera as linhas novas, uma depois da outra.
  • A diferença entre um INSERT com várias linhas e vários INSERT seguidos.
  • O "tudo ou nada": por que uma linha com erro barra o comando inteiro.
  • Como cadastrar um pedido novo e os seus itens, em duas tabelas.
  • RETURNING: ver na hora os id que o banco escolheu.
  • Os erros mais comuns: vírgula faltando, vírgula sobrando, linhas de tamanhos diferentes.

Como sempre no editor do guia, cada Rodar começa do banco limpo: pode inserir à vontade. Por isso cada exemplo termina com um SELECT para você ver as linhas novas.


A ideia: uma pilha de fichas de uma vez

Em vez de ir ao fichário três vezes, uma ficha por viagem, a Ana preenche três fichas na mesa e guarda a pilha inteira de uma vez. Se uma das fichas estiver rasurada, ela não guarda a pilha: corrige primeiro e guarda tudo junto. É assim que o INSERT com várias linhas funciona.

Uma linha por vezVárias linhas de uma vez
INSERT INTO t (a) VALUES (1);
INSERT INTO t (a) VALUES (2);
INSERT INTO t (a) VALUES (3);
INSERT INTO t (a) VALUES (1), (2), (3);
Três comandos: cada um entra (ou falha) sozinhoUm comando: as três entram juntas, ou nenhuma entra

1. Três categorias num INSERT só

A Aurora vai abrir três seções: Pet Shop, Automotivo e Beleza.

INSERT INTO categorias (nome, descricao) VALUES
  ('Pet Shop',   'Ração, brinquedos e acessórios para animais'),
  ('Automotivo', 'Acessórios para o carro'),
  ('Beleza',     'Cosméticos e cuidados pessoais');

SELECT * FROM categorias WHERE id > 6;
INSERT INTO categorias (nome, descricao)
Igual ao INSERT de uma linha: a tabela e a lista de colunas, escrita uma vez só. Ela vale para todas as linhas.
VALUES
Também aparece uma vez só.
('Pet Shop', '…'),
A primeira linha: uma lista de valores entre parênteses, na ordem das colunas. A vírgula depois do parêntese avisa que vem mais uma linha.
('Automotivo', '…'),
A segunda linha, também seguida de vírgula.
('Beleza', '…');
A última linha termina com ; e sem vírgula: depois dela não vem mais nada.

O quadro mostra "3 linhas afetadas": um comando, três linhas. E os id saíram em sequência, 9, 10 e 11, na ordem em que as linhas foram escritas: cada uma ganhou "o maior id que existe, mais 1", no momento em que entrou.

Os espaços a mais depois de 'Pet Shop', são só para alinhar as colunas e facilitar a leitura; o SQL ignora espaços e quebras de linha fora das aspas. Uma linha por registro, com os valores alinhados, é o jeito mais fácil de conferir um cadastro grande.

Experimente: o INSERT abaixo cadastra só a Pet Shop. Acrescente, no mesmo comando, mais duas categorias: Automotivo e Beleza (a descrição você escolhe). Lembre da vírgula entre as linhas.

INSERT INTO categorias (nome, descricao) VALUES
  ('Pet Shop', 'Ração, brinquedos e acessórios para animais');

SELECT * FROM categorias;
INSERT INTO categorias (nome, descricao) VALUES
  ('Pet Shop', 'Ração, brinquedos e acessórios para animais'),
  ('Automotivo', 'Acessórios para o carro'),
  ('Beleza', 'Cosméticos e cuidados pessoais');

SELECT * FROM categorias;

2. Várias linhas, com brancos

As regras de uma linha valem para cada linha da lista. Três clientes novos, um deles sem email:

INSERT INTO clientes (nome, email, cidade, estado) VALUES
  ('Lívia Rocha',   'livia.rocha@exemplo.com.br',   'Teresina', 'PI'),
  ('Joaquim Leite', NULL,                           'Picos',    'PI'),
  ('Bianca Moraes', 'bianca.moraes@exemplo.com.br', 'Parnaíba', 'PI');

SELECT * FROM clientes WHERE id > 30;
  • Todas as linhas têm quatro valores, porque a lista de colunas tem quatro. Para deixar o email do Joaquim em branco, a linha dele usa NULL no lugar do email; não dá para simplesmente "pular" o valor.
  • As colunas que não estão na lista (nascimento e vip) ficaram com NULL e com o padrão 0 nas três linhas.

3. Um pedido completo: duas tabelas

O cliente 27, Paulo Sérgio Andrade, que nunca tinha comprado na Aurora, fez o primeiro pedido: 2 cadernos, 5 lápis e 1 estojo, atendido pela Renata (funcionária 3). Na Aurora, um pedido mora em duas tabelas: o "cabeçalho" em pedidos e cada produto em itens_pedido (aula Tabelas que se Relacionam). Primeiro o cabeçalho, que vai ganhar o id 91; depois os três itens, que apontam para ele:

INSERT INTO pedidos (cliente_id, funcionario_id, data, frete)
VALUES (27, 3, '2026-10-16', 12.5);

INSERT INTO itens_pedido (pedido_id, produto_id, quantidade, preco_unitario) VALUES
  (91, 1, 2, 12.35),
  (91, 3, 5, 1.15),
  (91, 6, 1, 19.5);

SELECT * FROM pedidos WHERE id = 91;
SELECT * FROM itens_pedido WHERE pedido_id = 91;
  1. O primeiro INSERT cria o pedido. O entregue_em ficou de fora, então o pedido nasce NULL nesse campo: ainda não foi entregue.
  2. O segundo INSERT grava os três itens de uma vez. Cada linha diz o pedido (91), o produto (1 = caderno, 3 = lápis, 6 = estojo), a quantidade e o preço daquele dia.
  3. Os dois SELECT mostram o pedido e os itens. O editor mostra um quadro para cada comando, na ordem.

A ordem importa: os itens apontam para o pedido 91 (é uma chave estrangeira), então o pedido precisa existir antes. Com os itens primeiro, o SQLite do editor responderia FOREIGN KEY constraint failed.

E se o número do pedido não fosse 91?

Aqui a Ana sabe que o próximo pedido é o 91 porque o banco do editor é sempre o mesmo. Num sistema de verdade, com muita gente comprando ao mesmo tempo, ela pediria ao banco o número que ele acabou de escolher, com o RETURNING da seção 6, e usaria esse número nos itens. Os programas fazem isso com parâmetros (aula Consultas com Parâmetros).


4. Um INSERT com várias linhas × vários INSERT

As duas formas cadastram as mesmas linhas quando tudo dá certo. A diferença aparece quando alguma coisa dá errado.

Um comando: tudo ou nada

A Ana quer cadastrar duas categorias, escolhendo os números à mão, e erra o segundo: o 8 já existe (é a Jardim).

INSERT INTO categorias (id, nome) VALUES
  (9, 'Pet Shop'),
  (8, 'Automotivo');

A mensagem: UNIQUE constraint failed: categorias.id. E a Pet Shop, que estava certa, entrou? Não. Um comando SQL é atômico (de "átomo", o que não se divide): ou ele faz tudo, ou não faz nada. Como a segunda linha falhou, o SQLite desfez a primeira.

Vários comandos: cada um por si

Com dois INSERT separados, o primeiro já está gravado quando o segundo falha. No editor, a execução para no erro, então não dá para pôr um SELECT depois. No terminal, onde as mudanças ficam no arquivo, dá para ver a diferença com clareza:

$ sqlite3 loja.db
SQLite version 3.50.4 2025-07-30 19:33:53
Enter ".help" for usage hints.
sqlite> INSERT INTO categorias (id, nome) VALUES (9, 'Pet Shop'), (8, 'Automotivo');
Runtime error: UNIQUE constraint failed: categorias.id (19)
sqlite> SELECT id, nome FROM categorias WHERE id > 7;
8|Jardim                     « um comando só: a Pet Shop também não entrou
sqlite> INSERT INTO categorias (id, nome) VALUES (9, 'Pet Shop');
sqlite> INSERT INTO categorias (id, nome) VALUES (8, 'Automotivo');
Runtime error: UNIQUE constraint failed: categorias.id (19)
sqlite> SELECT id, nome FROM categorias WHERE id > 7;
8|Jardim
9|Pet Shop                   « dois comandos: o primeiro ficou gravado
sqlite> .quit

Qual é melhor? Depende do que você quer quando algo dá errado. Para um pedido e os seus itens, o "tudo ou nada" é o que você quer: um pedido com só metade dos itens é pior do que pedido nenhum. Para isso, junte as linhas num comando só. Quando são vários comandos que precisam dar certo juntos (como o pedido e os itens, que estão em tabelas diferentes), o SQL tem as transações, que fazem um grupo de comandos virar um "tudo ou nada": aula Transações (BEGIN e COMMIT).

Um INSERT, várias linhasVários INSERT
Uma linha com erroNenhuma linha entraAs anteriores ficam; a com erro e as seguintes não entram
Tabelas diferentesNão dá: um INSERT só grava numa tabelaDá
Tamanho do SQLCurto: tabela e colunas escritas uma vezRepete o começo em cada linha
Velocidade com muitas linhasMais rápidoMais lento (cada comando é uma gravação; fica rápido dentro de uma transação)

5. Vendo quantas linhas mudaram

O editor escreve "3 linhas afetadas". No terminal, o INSERT fica quieto quando dá certo; para ver a contagem, ligue o comando de ponto .changes on:

$ sqlite3 loja.db
SQLite version 3.50.4 2025-07-30 19:33:53
Enter ".help" for usage hints.
sqlite> .changes on
sqlite> INSERT INTO categorias (nome) VALUES ('Automotivo'), ('Beleza'), ('Brinquedos Educativos');
changes: 3   total_changes: 3
sqlite> .quit

changes: 3 é quanto o último comando mudou; total_changes é a soma desde que você abriu o sqlite3. Com .changes on, o terminal repete essa linha depois de todo comando, até de um SELECT (que não muda nada e mostra os mesmos números). Desligue com .changes off.


6. RETURNING: ver os ids na hora

Depois do INSERT, você quer saber que id cada linha recebeu. Em vez de um SELECT separado, o SQLite aceita RETURNING ("devolvendo") no fim do INSERT: ele devolve as colunas que você pedir, das linhas que acabaram de entrar.

INSERT INTO clientes (nome, cidade, estado) VALUES
  ('Lívia Rocha',   'Teresina', 'PI'),
  ('Joaquim Leite', 'Picos',    'PI')
RETURNING id, nome;
RETURNING id, nome
Vem depois da última linha de valores, antes do ;. Funciona como a lista de colunas de um SELECT: RETURNING * devolve todas.

A resposta é uma tabela com as duas linhas novas: 31 e 32. É assim que um programa descobre o número do pedido recém-criado para gravar os itens. O RETURNING também funciona com UPDATE e DELETE, e é um ótimo aliado contra acidentes: a aula O Perigo do UPDATE e DELETE sem WHERE mostra como.


Formas diferentes de inserir várias linhas

FormaQuando usar
INSERT INTO t (…) VALUES (…), (…), (…);Várias linhas da mesma tabela que devem entrar juntas. A forma mais comum.
Vários INSERT seguidosLinhas em tabelas diferentes (o pedido e os itens), ou quando cada linha pode entrar sozinha.
Vários INSERT dentro de uma transaçãoVários comandos que precisam dar certo juntos: aula Transações.
INSERT INTO t (…) SELECT …As linhas novas vêm de uma consulta em outra tabela: aula INSERT INTO SELECT.
.import arquivo.csv tabela (terminal)Centenas ou milhares de linhas vindas de uma planilha: aula Importar e Exportar CSV.

Quando dá errado

Em todos estes casos, o comando inteiro é recusado: nenhuma das linhas entra.

Linhas com quantidades diferentes de valores
INSERT INTO categorias (nome, descricao) VALUES
  ('Pet Shop', 'Ração, brinquedos e acessórios para animais'),
  ('Automotivo');

A mensagem: all VALUES must have the same number of terms ("todos os VALUES precisam ter o mesmo número de termos"). A segunda linha tem um valor só, e a primeira tem dois.

Como consertar: todas as linhas com um valor para cada coluna da lista. Para deixar a descrição em branco, use NULL: ('Automotivo', NULL).

Faltou a vírgula entre as linhas
INSERT INTO categorias (nome) VALUES
  ('Pet Shop')
  ('Automotivo');

A mensagem: near "(": syntax error. Depois de ('Pet Shop'), o SQLite esperava uma vírgula (mais uma linha) ou o fim do comando, e encontrou outro parêntese.

Como consertar: vírgula depois de cada linha, menos a última.

Sobrou uma vírgula no fim
INSERT INTO categorias (nome) VALUES
  ('Pet Shop'),
  ('Automotivo'),
;

A mensagem: near ";": syntax error. A vírgula prometeu mais uma linha, e chegou o fim do comando. Acontece muito quando você apaga a última linha de uma lista e esquece a vírgula da penúltima.

Como consertar: a última linha termina com ) e ;, sem vírgula.

O mesmo produto duas vezes no pedido
INSERT INTO itens_pedido (pedido_id, produto_id, quantidade, preco_unitario) VALUES
  (90, 1, 1, 12.35),
  (90, 1, 2, 12.35);

A mensagem: UNIQUE constraint failed: itens_pedido.pedido_id, itens_pedido.produto_id. Na tabela itens_pedido, a chave primária é o par (pedido, produto): cada produto aparece uma vez por pedido. A mensagem cita as duas colunas porque é a combinação delas que se repetiu.

Como consertar: uma linha por produto, com a quantidade total: (90, 1, 3, 12.35).

Uma linha com um campo obrigatório vazio
INSERT INTO categorias (nome) VALUES
  ('Pet Shop'),
  (NULL);

A mensagem: NOT NULL constraint failed: categorias.nome. Basta uma linha quebrar a regra para o comando todo ser recusado; a Pet Shop também não entra.

Missão: este cadastro de dois clientes não roda. Leia a mensagem, conserte e rode até os dois entrarem.

INSERT INTO clientes (nome, cidade, estado) VALUES
  ('Lívia Rocha', 'Teresina', 'PI')
  ('Joaquim Leite', 'Picos', 'PI'),
;

SELECT id, nome, cidade FROM clientes WHERE id > 29;
INSERT INTO clientes (nome, cidade, estado) VALUES
  ('Lívia Rocha', 'Teresina', 'PI'),
  ('Joaquim Leite', 'Picos', 'PI');

SELECT id, nome, cidade FROM clientes WHERE id > 29;
Nos outros bancos
  • O VALUES (…), (…) com várias linhas é do SQL padrão e funciona no MySQL, no PostgreSQL e no SQL Server. No SQL Server, a documentação limita um INSERT … VALUES a 1.000 linhas; para mais, use vários comandos ou importação em massa.
  • O SQL Server (e o MySQL e o PostgreSQL) aceitam a palavra DEFAULT no lugar de um valor, para pedir o valor padrão daquela coluna numa linha. O SQLite não aceita: VALUES ('Lívia Rocha', DEFAULT) dá near "DEFAULT": syntax error. No SQLite, para usar o padrão, deixe a coluna fora da lista. Trecho só ilustrativo:
    INSERT INTO clientes (nome, vip)
    VALUES ('Lívia Rocha', DEFAULT), ('Joaquim Leite', 1);
    
  • O RETURNING existe também no PostgreSQL. No SQL Server, o equivalente é a cláusula OUTPUT.

Referência rápida

EscritaO que faz
INSERT INTO t (a, b) VALUES (1, 'x'), (2, 'y');Duas linhas num comando
Vírgula entre as listasSepara as linhas; a última não leva vírgula
NULL numa posiçãoDeixa aquele campo em branco naquela linha
Uma linha com erroO comando inteiro é recusado (atômico)
… RETURNING id, nome;Devolve as linhas que acabaram de entrar
.changes on (terminal)Mostra quantas linhas cada comando mudou
Mensagem do SQLite (editor)Quer dizer
all VALUES must have the same number of termsLinhas com quantidades diferentes de valores
near "(": syntax errorFaltou a vírgula entre duas linhas
near ";": syntax errorSobrou vírgula depois da última linha
UNIQUE constraint failed: itens_pedido.pedido_id, itens_pedido.produto_idO mesmo par (pedido, produto) duas vezes
near "DEFAULT": syntax errorO SQLite não aceita DEFAULT dentro do VALUES

Exercícios

1. A vírgula que falta

Complete com o caractere que separa as duas linhas:

INSERT INTO categorias (nome) VALUES ('Pet Shop') ('Beleza');

2. A maior categoria é a 8. Que id ganham as linhas de INSERT INTO categorias (nome) VALUES ('A'), ('B'), ('C');?

3. Um INSERT com três linhas tem um erro na terceira. Quantas linhas entram?

4. Por que o pedido novo precisa ser inserido antes dos seus itens?

Missão final: o primeiro pedido da Tainá

Missão: a cliente 28, Tainá Soares, fez o primeiro pedido, no dia 2026-10-17, atendida pelo funcionário 2, com frete de 9.9. O cabeçalho do pedido já está escrito abaixo (ele vai ganhar o número 91). Acrescente, num único INSERT em itens_pedido, os dois itens: 1 Garrafa Térmica 1L (produto 15, a 54.3) e 2 Cafés Torrados 500g (produto 35, a 23.85).

INSERT INTO pedidos (cliente_id, funcionario_id, data, frete)
VALUES (28, 2, '2026-10-17', 9.9);

SELECT * FROM itens_pedido WHERE pedido_id = 91;
INSERT INTO pedidos (cliente_id, funcionario_id, data, frete)
VALUES (28, 2, '2026-10-17', 9.9);

INSERT INTO itens_pedido (pedido_id, produto_id, quantidade, preco_unitario) VALUES
  (91, 15, 1, 54.3),
  (91, 35, 2, 23.85);

SELECT * FROM itens_pedido WHERE pedido_id = 91;

Resumo

  • Várias linhas num INSERT: VALUES (…), (…), (…);, com a tabela e as colunas escritas uma vez.
  • Vírgula entre as linhas, nenhuma depois da última. Todas as linhas com o mesmo número de valores (use NULL para o branco).
  • Os id automáticos saem em sequência, na ordem das linhas.
  • Um comando é atômico: se uma linha falha, nenhuma entra. Vários INSERT seguidos não são: os anteriores ao erro ficam.
  • Linhas em tabelas diferentes (pedido e itens) precisam de comandos separados, na ordem certa por causa das chaves estrangeiras. Para "tudo ou nada" entre vários comandos, use uma transação.
  • RETURNING devolve as linhas que acabaram de entrar, com os id escolhidos pelo banco.