sqlpostgresqlstringsrepeat

REPEAT en SQL: repetir cadenas para separadores, placeholders y graficos de barras

Como REPEAT(str, n) repite una cadena n veces y por que es una herramienta util para separadores, placeholders y graficos de barras en SQL.

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

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);   -- ababab
SELECT REPEAT('-', 20);   -- a 20-dash rule
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.

Separadores y cabeceras de informe

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.

-- 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, 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);    -- '' (empty string)
SELECT REPEAT('x', -5);   -- '' (empty string)

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.

Practica con ejercicios reales

Resuelve ejercicios en el entrenador de SQL con corrección instantánea y pistas.

Abrir el entrenador