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);
SELECT REPEAT('-', 20);
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.
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.
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);
SELECT REPEAT('x', -5);
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.
REPEAT(str, n)retorna uma string comstrcolada a si mesmanvezes 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
textpuro.SELECT REPEAT('ab', 3); -- ababab SELECT REPEAT('-', 20); -- a 20-dash rule SELECT REPEAT(' ', 4) || 'indented';Coisas que vale a pena lembrar:
REPEAT('=-', 5)gera=-=-=-=-=-.||e outro texto.REPEAT('0', 3)e'000', nao o numero0.No PostgreSQL e no MySQL a funcao tem o mesmo nome e o mesmo comportamento:
REPEAT(str, n). O ClickHouse oferecerepeat(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.
REPEATevita 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, $3para um array de parametros de tamanho variavel.REPEATconstroi o esqueleto, e o separador sobrando no fim e cortado comTRIMouRTRIM.-- 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, adicioneLPAD, 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;REPEATdesenha a barra, eLPAD(..., 30)garante que cada linha tem exatamente 30 caracteres, entao o grafico nunca sai do lugar. A combinacaoREPEAT+LPAD/RPADe o burro de carga para visualizacoes ASCII.Casos limite com n <= 0
Aqui se esconde a pegadinha principal. Se
nfor zero ou negativo,REPEATretorna uma string vazia, naoNULLe nem um erro.SELECT REPEAT('x', 0); -- '' (empty string) SELECT REPEAT('x', -5); -- '' (empty string)Dai saem algumas consequencias:
0blocos desenha uma string vazia, entao a barra fica invisivel. Se voce quer ao menos um marcador, force um minimo:REPEAT('#', GREATEST(value, 1)).nacaba sendoNULL(por exemplo, por causa de umNULLnos dados), todo o resultado deREPEATviraNULL. Proteja comCOALESCE(n, 0).nfracionario e arredondado/truncado em silencio para um inteiro, entao calculenantes e converta-o explicitamente com::int.Pegadinha: e facil confundir
REPEATcom concatenacao.REPEAT('ab', 3)e'ababab'(uma unica string de seis caracteres), nao tres linhas separadas. Se voce realmente quer linhas de tabela, usegenerate_seriese reserveREPEATpara formatar texto.