sqlpostgresqlstringsrepeat

REPEAT no SQL: repetir strings para separadores, placeholders e graficos de barras

Como REPEAT(str, n) repete uma string n vezes e por que e uma ferramenta util para separadores, placeholders e graficos de barras no SQL.

3 min de leituraReferencesql · postgresql · strings · repeat · mysql · formatting

REPEAT(str, n) retorna uma string com str colada a si mesma n vezes seguidas. A funcao parece trivial, mas e a peca base para separadores de relatorio, placeholders em consultas dinamicas e graficos de texto compactos desenhados direto na saida SQL.

Sintaxe basica

Recebe dois argumentos: o que repetir e quantas vezes. O resultado e text puro.

SELECT REPEAT('ab', 3);   -- ababab
SELECT REPEAT('-', 20);   -- a 20-dash rule
SELECT REPEAT(' ', 4) || 'indented';

Coisas que vale a pena lembrar:

  • Repete-se qualquer string, nao apenas um caractere: REPEAT('=-', 5) gera =-=-=-=-=-.
  • O resultado concatena de forma limpa com || e outro texto.
  • O tipo retornado e sempre string, mesmo com digitos dentro: REPEAT('0', 3) e '000', nao o numero 0.

No PostgreSQL e no MySQL a funcao tem o mesmo nome e o mesmo comportamento: REPEAT(str, n). O ClickHouse oferece repeat(s, n) com o mesmo significado.

Separadores e cabecalhos de relatorio

Quando um relatorio vai para um console ou um dump de texto, regras limpas o deixam legivel. REPEAT evita que voce escreva na mao longas sequencias de tracos.

SELECT REPEAT('=', 40) AS header_rule
UNION ALL
SELECT '  MONTHLY REVENUE REPORT'
UNION ALL
SELECT REPEAT('=', 40);

Voce pode amarrar o comprimento da regua aos dados, por exemplo ao nome mais longo, para que o sublinhado bata exatamente com a largura dele:

SELECT
  name,
  REPEAT('-', LENGTH(name)) AS underline
FROM users
ORDER BY name
LIMIT 5;

Placeholders para consultas dinamicas

As vezes voce precisa montar uma lista como ?, ?, ? ou $1, $2, $3 para um array de parametros de tamanho variavel. REPEAT constroi o esqueleto, e o separador sobrando no fim e cortado com TRIM ou RTRIM.

-- Build "?,?,?" for an IN-list of 3 values
SELECT RTRIM(REPEAT('?,', 3), ',');   -- ?,?,?

O mesmo truque serve para os placeholders numerados do PostgreSQL quando o codigo da aplicacao os gera e voce so quer conferir o formato da string. A regra pratica: repita "item mais separador" e depois corte o separador final, assim voce nunca briga com "nao colocar virgula depois do ultimo".

Graficos de barras de texto e LPAD

O caso mais vistoso e um mini histograma dentro do proprio resultado. Pegue uma metrica numerica, divida por uma escala e desenhe tantos blocos quantos sairem.

SELECT
  country,
  COUNT(*)                              AS users_cnt,
  REPEAT('#', (COUNT(*) / 10)::int)     AS bar
FROM users
GROUP BY country
ORDER BY users_cnt DESC;

Cada # aqui representa 10 usuarios. Para alinhar as barras em uma coluna arrumada, adicione LPAD, que preenche uma string com espacos a esquerda ate uma largura fixa:

SELECT
  dept,
  ROUND(AVG(salary))                                  AS avg_salary,
  LPAD(REPEAT('#', (AVG(salary) / 1000)::int), 30)    AS bar
FROM employees
GROUP BY dept
ORDER BY avg_salary DESC;

REPEAT desenha a barra, e LPAD(..., 30) garante que cada linha tem exatamente 30 caracteres, entao o grafico nunca sai do lugar. A combinacao REPEAT + LPAD/RPAD e o burro de carga para visualizacoes ASCII.

Casos limite com n <= 0

Aqui se esconde a pegadinha principal. Se n for zero ou negativo, REPEAT retorna uma string vazia, nao NULL e nem um erro.

SELECT REPEAT('x', 0);    -- '' (empty string)
SELECT REPEAT('x', -5);   -- '' (empty string)

Dai saem algumas consequencias:

  • Em um grafico de barras, uma metrica que da 0 blocos desenha uma string vazia, entao a barra fica invisivel. Se voce quer ao menos um marcador, force um minimo: REPEAT('#', GREATEST(value, 1)).
  • Se n acaba sendo NULL (por exemplo, por causa de um NULL nos dados), todo o resultado de REPEAT vira NULL. Proteja com COALESCE(n, 0).
  • Um n fracionario e arredondado/truncado em silencio para um inteiro, entao calcule n antes e converta-o explicitamente com ::int.

Pegadinha: e facil confundir REPEAT com concatenacao. REPEAT('ab', 3) e 'ababab' (uma unica string de seis caracteres), nao tres linhas separadas. Se voce realmente quer linhas de tabela, use generate_series e reserve REPEAT para formatar texto.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador