REPEAT(str, n) devuelve una cadena con str pegada a si misma n veces seguidas. La funcion suena trivial, pero es la pieza base para separadores de informes, placeholders en consultas dinamicas y graficos de texto compactos dibujados directamente en la salida SQL.
Sintaxis basica
Recibe dos argumentos: que repetir y cuantas veces. El resultado es text plano.
SELECT REPEAT('ab', 3);
SELECT REPEAT('-', 20);
SELECT REPEAT(' ', 4) || 'indented';
Cosas que conviene recordar:
- Se repite cualquier cadena, no solo un caracter:
REPEAT('=-', 5) da =-=-=-=-=-.
- El resultado se concatena limpiamente con
|| y otro texto.
- El tipo devuelto siempre es cadena, aunque lleve digitos dentro:
REPEAT('0', 3) es '000', no el numero 0.
En PostgreSQL y MySQL la funcion se llama e se comporta igual: REPEAT(str, n). ClickHouse ofrece repeat(s, n) con el mismo significado.
Cuando un informe va a una consola o a un volcado de texto, unas reglas limpias lo hacen legible. REPEAT te ahorra escribir a mano cadenas largas de guiones.
SELECT REPEAT('=', 40) AS header_rule
UNION ALL
SELECT ' MONTHLY REVENUE REPORT'
UNION ALL
SELECT REPEAT('=', 40);
Puedes atar la longitud de la regla a los datos, por ejemplo al nombre mas largo, para que el subrayado coincida exactamente con su ancho:
SELECT
name,
REPEAT('-', LENGTH(name)) AS underline
FROM users
ORDER BY name
LIMIT 5;
Placeholders para consultas dinamicas
A veces necesitas montar una lista como ?, ?, ? o $1, $2, $3 para un array de parametros de longitud variable. REPEAT construye el esqueleto, y el separador sobrante del final se recorta con TRIM o RTRIM.
SELECT RTRIM(REPEAT('?,', 3), ',');
El mismo truco sirve para los placeholders numerados de PostgreSQL cuando el codigo de la aplicacion los genera y tu solo quieres comprobar la forma de la cadena. La regla practica: repite "elemento mas separador" y luego recorta el separador final, asi nunca peleas con "no poner coma despues del ultimo".
Graficos de barras de texto y LPAD
El caso mas vistoso es un mini histograma dentro del propio resultado. Toma una metrica numerica, divide por una escala y dibuja tantos bloques como salgan.
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 alinear las barras en una columna ordenada, anade LPAD, que rellena una cadena con espacios a la izquierda hasta un ancho fijo:
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 dibuja la barra, y LPAD(..., 30) garantiza que cada fila mide exactamente 30 caracteres, asi el grafico nunca se descuadra. La combinacion REPEAT + LPAD/RPAD es el caballo de batalla para las visualizaciones ASCII.
Casos limite con n <= 0
Aqui se esconde la trampa principal. Si n es cero o negativo, REPEAT devuelve una cadena vacia, no NULL ni un error.
SELECT REPEAT('x', 0);
SELECT REPEAT('x', -5);
De ahi salen varias consecuencias:
- En un grafico de barras, una metrica que da
0 bloques dibuja una cadena vacia, asi que la barra es invisible. Si quieres al menos un marcador, fuerza un minimo: REPEAT('#', GREATEST(value, 1)).
- Si
n resulta ser NULL (por ejemplo, por un NULL en los datos), todo el resultado de REPEAT pasa a NULL. Protegelo con COALESCE(n, 0).
- Un
n fraccionario se redondea/trunca en silencio a un entero, asi que calcula n de antemano y conviertelo explicitamente con ::int.
Trampa: es facil confundir REPEAT con la concatenacion. REPEAT('ab', 3) es 'ababab' (una sola cadena de seis caracteres), no tres filas separadas. Si de verdad quieres filas de tabla, usa generate_series y reserva REPEAT para dar formato al texto.
REPEAT(str, n)devuelve una cadena constrpegada a si mismanveces seguidas. La funcion suena trivial, pero es la pieza base para separadores de informes, placeholders en consultas dinamicas y graficos de texto compactos dibujados directamente en la salida SQL.Sintaxis basica
Recibe dos argumentos: que repetir y cuantas veces. El resultado es
textplano.SELECT REPEAT('ab', 3); -- ababab SELECT REPEAT('-', 20); -- a 20-dash rule SELECT REPEAT(' ', 4) || 'indented';Cosas que conviene recordar:
REPEAT('=-', 5)da=-=-=-=-=-.||y otro texto.REPEAT('0', 3)es'000', no el numero0.En PostgreSQL y MySQL la funcion se llama e se comporta igual:
REPEAT(str, n). ClickHouse ofrecerepeat(s, n)con el mismo significado.Separadores y cabeceras de informe
Cuando un informe va a una consola o a un volcado de texto, unas reglas limpias lo hacen legible.
REPEATte ahorra escribir a mano cadenas largas de guiones.SELECT REPEAT('=', 40) AS header_rule UNION ALL SELECT ' MONTHLY REVENUE REPORT' UNION ALL SELECT REPEAT('=', 40);Puedes atar la longitud de la regla a los datos, por ejemplo al nombre mas largo, para que el subrayado coincida exactamente con su ancho:
SELECT name, REPEAT('-', LENGTH(name)) AS underline FROM users ORDER BY name LIMIT 5;Placeholders para consultas dinamicas
A veces necesitas montar una lista como
?, ?, ?o$1, $2, $3para un array de parametros de longitud variable.REPEATconstruye el esqueleto, y el separador sobrante del final se recorta conTRIMoRTRIM.-- Build "?,?,?" for an IN-list of 3 values SELECT RTRIM(REPEAT('?,', 3), ','); -- ?,?,?El mismo truco sirve para los placeholders numerados de PostgreSQL cuando el codigo de la aplicacion los genera y tu solo quieres comprobar la forma de la cadena. La regla practica: repite "elemento mas separador" y luego recorta el separador final, asi nunca peleas con "no poner coma despues del ultimo".
Graficos de barras de texto y LPAD
El caso mas vistoso es un mini histograma dentro del propio resultado. Toma una metrica numerica, divide por una escala y dibuja tantos bloques como salgan.
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 alinear las barras en una columna ordenada, anadeLPAD, que rellena una cadena con espacios a la izquierda hasta un ancho fijo: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;REPEATdibuja la barra, yLPAD(..., 30)garantiza que cada fila mide exactamente 30 caracteres, asi el grafico nunca se descuadra. La combinacionREPEAT+LPAD/RPADes el caballo de batalla para las visualizaciones ASCII.Casos limite con n <= 0
Aqui se esconde la trampa principal. Si
nes cero o negativo,REPEATdevuelve una cadena vacia, noNULLni un error.SELECT REPEAT('x', 0); -- '' (empty string) SELECT REPEAT('x', -5); -- '' (empty string)De ahi salen varias consecuencias:
0bloques dibuja una cadena vacia, asi que la barra es invisible. Si quieres al menos un marcador, fuerza un minimo:REPEAT('#', GREATEST(value, 1)).nresulta serNULL(por ejemplo, por unNULLen los datos), todo el resultado deREPEATpasa aNULL. Protegelo conCOALESCE(n, 0).nfraccionario se redondea/trunca en silencio a un entero, asi que calculande antemano y conviertelo explicitamente con::int.Trampa: es facil confundir
REPEATcon la concatenacion.REPEAT('ab', 3)es'ababab'(una sola cadena de seis caracteres), no tres filas separadas. Si de verdad quieres filas de tabla, usagenerate_seriesy reservaREPEATpara dar formato al texto.