O SUBSTRING retorna parte de uma string, começando na posição que você indicar e seguindo por quantos caracteres você pedir. É assim que o SQL extrai um prefixo, um código ou o domínio de um email de uma coluna de texto. Os exemplos funcionam no PostgreSQL, MySQL, SQLite e SQL Server.
Como usar o SUBSTRING
Passe ao SUBSTRING uma string, a posição inicial (o primeiro caractere é 1) e quantos caracteres pegar. Omita o tamanho para pegar tudo até o final:
SUBSTRING(string, start, length)
SELECT SUBSTRING('Joe Bloggs', 1, 3);
-- Output: Joe
-- No length: the rest of the string (SQL Server needs all three arguments)
SELECT SUBSTRING('Joe Bloggs', 5);
-- Output: Bloggs
Em uma consulta real, a string geralmente é uma coluna. Números de pedido como ORD-2024-001 guardam o ano nos caracteres 5 a 8:
-- Input: orders
-- order_number
-- ------------
-- ORD-2024-001
-- ORD-2025-014
-- ORD-2026-102
SELECT order_number, SUBSTRING(order_number, 5, 4) AS year
FROM orders;
-- Output:
-- order_number | year
-- -------------+-----
-- ORD-2024-001 | 2024
-- ORD-2025-014 | 2025
-- ORD-2026-102 | 2026
Regras importantes
- As posições começam em 1, não em 0. Um início negativo conta a partir do final da string, mas só no MySQL e no SQLite:
SELECT SUBSTRING('Joe Bloggs', -6, 6);
-- Output: Bloggs
-- PostgreSQL and SQL Server return '' (an empty string) instead
- Passar do final não gera erro. Você recebe os caracteres que existem, ou uma string vazia quando o início está além do final:
SELECT SUBSTRING('Bob', 1, 10);
-- Output: Bob
SELECT SUBSTRING('Hello', 10, 5);
-- Output: '' (an empty string)
- Entra NULL, sai NULL. Envolva a chamada em COALESCE quando precisar de um valor:
SELECT SUBSTRING(NULL, 1, 5);
-- Output: NULL
-- SQL Server rejects a bare NULL here, but a NULL column gives NULL
-
Filtre por prefixo com LIKE, não com SUBSTRING.
WHERE SUBSTRING(product_code, 1, 3) = 'ELE'retorna as mesmas linhas queWHERE product_code LIKE 'ELE%', mas só a versão com LIKE consegue usar um índice emproduct_code.
Sintaxe alternativa
Você também verá SUBSTR, outro nome para o SUBSTRING, e LEFT e RIGHT, que pegam caracteres de cada uma das pontas:
-- Not in SQL Server
SELECT SUBSTR('Joe Bloggs', 1, 3);
-- Output: Joe
-- Not in SQLite: use SUBSTRING('Joe Bloggs', 1, 3) and SUBSTRING('Joe Bloggs', -6)
SELECT LEFT('Joe Bloggs', 3);
-- Output: Joe
SELECT RIGHT('Joe Bloggs', 6);
-- Output: Bloggs
-- PostgreSQL and MySQL: the standard SQL form
SELECT SUBSTRING('Joe Bloggs' FROM 1 FOR 3);
-- Output: Joe
Para começar depois de um caractere específico, encontre a posição dele primeiro:
SELECT INSTR('joe@example.com', '@');
-- Output: 4
-- PostgreSQL: POSITION('@' IN 'joe@example.com'); SQL Server: CHARINDEX('@', 'joe@example.com')
Quando usar o SUBSTRING?
Use o SUBSTRING quando a parte da string que você precisa está em uma posição conhecida, ou logo depois de um caractere que você consegue encontrar. A maioria dos usos se encaixa em um destes quatro casos.
Pegar os primeiros caracteres
Códigos e nomes costumam ter significado no início: a categoria em um código de produto, uma inicial, uma prévia curta de uma descrição longa. SUBSTRING(column, 1, n) pega os primeiros n caracteres.
Extrair campos de valores com formato fixo
Quando todos os valores têm o mesmo layout, cada parte fica na mesma posição em todas as linhas: o código de área em um telefone como (303) 555-0147, o ano em ORD-2024-001 ou os campos de um registro de largura fixa vindo de um sistema antigo.
Extrair texto depois de um delimitador
Domínios de email, extensões de arquivo e caminhos de URL começam depois de um caractere cuja posição muda de linha para linha. Encontre a posição dele com INSTR, comece um caractere depois e pegue o resto da string.
Manter os últimos caracteres
Mascarar um número de cartão ou de conta, ou ler um sufixo, significa contar a partir do final. Calcule o início a partir do tamanho da string ou, no MySQL e no SQLite, use um início negativo.
Exemplos reais de SUBSTRING
Contar produtos pela categoria no código
Os códigos de produto começam com uma categoria de três letras. Agrupe por esse prefixo para contar os produtos de cada uma:
-- Input: products
-- product_code | name
-- -------------+-----------
-- ELE-1234 | USB-C Hub
-- FUR-0087 | Desk Chair
-- ELE-5521 | Webcam
-- OFF-2210 | Stapler
SELECT SUBSTRING(product_code, 1, 3) AS category, COUNT(*) AS products
FROM products
GROUP BY SUBSTRING(product_code, 1, 3)
ORDER BY category;
-- Output:
-- category | products
-- ---------+---------
-- ELE | 2
-- FUR | 1
-- OFF | 1
Analisar um registro de largura fixa
Exportações de sistemas antigos costumam colocar os campos em posições fixas, sem delimitador. Aqui o nome ocupa 8 caracteres (preenchidos com espaços, que o TRIM remove), a data de nascimento os 8 seguintes e o código da cidade os últimos 3:
-- Input: legacy_data
-- record
-- -------------------
-- JOHNDOE 19850315NYC
-- MARYLEE 19780912CHI
-- JANEROE 19900722LAX
SELECT
TRIM(SUBSTRING(record, 1, 8)) AS name,
SUBSTRING(record, 9, 8) AS birth_date,
SUBSTRING(record, 17, 3) AS city_code
FROM legacy_data;
-- Output:
-- name | birth_date | city_code
-- --------+------------+----------
-- JOHNDOE | 19850315 | NYC
-- MARYLEE | 19780912 | CHI
-- JANEROE | 19900722 | LAX
Obter a extensão de cada arquivo
Encontre o ponto e pegue tudo depois dele. A cláusula WHERE ignora arquivos sem ponto:
-- Input: documents
-- filename
-- ---------------
-- q3-report.pdf
-- budget.xlsx
-- README
-- team-photo.jpeg
SELECT
filename,
SUBSTRING(filename, INSTR(filename, '.') + 1) AS extension
FROM documents
WHERE INSTR(filename, '.') > 0;
-- Output:
-- filename | extension
-- ----------------+----------
-- q3-report.pdf | pdf
-- budget.xlsx | xlsx
-- team-photo.jpeg | jpeg
No PostgreSQL, use POSITION('.' IN filename) em vez de INSTR. No SQL Server, use CHARINDEX('.', filename) e informe um tamanho, como LEN(filename).
Mascarar um número de cartão
Nem todo número de cartão tem 16 dígitos, então uma posição inicial fixa corta os números da American Express. Conte a partir do final:
-- Input: payments
-- customer_name | card_number
-- --------------+-----------------
-- Lena Fischer | 4111111111111111
-- Marcus Reid | 5500005555555559
-- Aiko Tanaka | 378282246310005
-- Wrong: position 13 only works for 16-digit cards
SELECT customer_name, '**** ' || SUBSTRING(card_number, 13, 4) AS masked_card
FROM payments;
-- Output:
-- customer_name | masked_card
-- --------------+------------
-- Lena Fischer | **** 1111
-- Marcus Reid | **** 5559
-- Aiko Tanaka | **** 005
-- Right: start 4 characters from the end
SELECT customer_name, '**** ' || SUBSTRING(card_number, LENGTH(card_number) - 3, 4) AS masked_card
FROM payments;
-- Output:
-- customer_name | masked_card
-- --------------+------------
-- Lena Fischer | **** 1111
-- Marcus Reid | **** 5559
-- Aiko Tanaka | **** 0005
No MySQL e no SQL Server, junte as strings com CONCAT() em vez de ||. O SQL Server também precisa de LEN() em vez de LENGTH().
Leituras complementares sobre SUBSTRING
Neste blog:
- Guia do LIKE no SQL: encontre texto que começa com, termina com ou contém um padrão
- Guia do COALESCE no SQL: substitua os NULLs que o SUBSTRING repassa
- Guia do GROUP BY no SQL: agrupe e conte linhas por um valor extraído
- Guia de formatação de datas no SQL: formate datas e extraia partes delas sem fatiar strings
Documentação oficial:
Beekeeper Studio é um cliente de banco de dados gratuito e open source
A melhor ferramenta de consultas e edição de SQL que já usei. Tem tudo o que preciso para gerenciar meu banco de dados. - ⭐⭐⭐⭐⭐ Mit
O Beekeeper Studio é rápido, intuitivo e fácil de usar. Ele suporta vários bancos de dados e funciona muito bem no Windows, Mac e Linux.
O que os usuários dizem sobre o Beekeeper Studio
"O Beekeeper Studio substituiu completamente meu antigo fluxo de trabalho com SQL. É rápido, intuitivo e torna o trabalho com banco de dados agradável de novo."
"Já experimentei muitas GUIs de banco de dados, mas o Beekeeper encontra o equilíbrio perfeito entre recursos e simplicidade. Simplesmente funciona."