sql >> Base de Datos >  >> RDS >> Mysql

SQL:imprime muchas palabras entre cada columna con muchas condiciones

Nuevo y mejorado (versión 3 cómo) usando variables y usando básicamente el mismo truco de aquí :

SELECT
  IF(is_real, '**ANY WORD**', full_name) AS full_name,
  IF(is_real, '', club_name) AS club_name
FROM
  (
    SELECT
      full_name,
      club_name,
      (@row_num2:= @row_num2 + 1) AS row_num
    FROM
      (
        SELECT p3.*
        FROM
          (
        SELECT
          p2.*,
          (@row_num := @row_num + 1) AS row_num
        FROM
          (
            SELECT *
            FROM players AS p1
            WHERE y_of_birth = 2000
          ) AS p2
        CROSS JOIN
          (
            SELECT
              @row_num := 0,
              @count := (SELECT COUNT(*) FROM players WHERE y_of_birth = 2000)
          ) AS vars
        ORDER BY club_name
      ) AS p3
    ORDER BY row_num % FLOOR(@row_num / 2), row_num
  ) AS p4
CROSS JOIN
  (
    SELECT
      @row_num2 := -1,
      @extra := GREATEST(2, POW(2, CEIL(LOG2(@count)))) - @count) AS vars
  ) AS data
LEFT JOIN
  (
    (SELECT 1 AS is_real)
    UNION ALL
    (SELECT 0 AS is_real)
  ) AS filler
ON
  MOD(row_num, FLOOR(@count / @extra)) = 0 AND
  row_num / FLOOR(@count / @extra) < @extra
ORDER BY row_num, is_real

Para los datos de ejemplo que proporcionó, esto produce algo como:

+--------------+-----------+
| full_name    | club_name |
+--------------+-----------+
| Ahmed Sayed  | El Ahly   |
| **ANY WORD** |           |
| Mohamed gad  | Ismaily   |
| **ANY WORD** |           |
| omar galal   | Cocorico  |
| **ANY WORD** |           |
| Kareem Gaber | El Ahly   |
| Kamal saber  | wadi dgla |
+--------------+-----------+

Esto debería funcionar para resultados de cualquier tamaño; simplemente cambie la condición (y_of_birth = 2000 ) para ser cualquier condición que desee. Actualicé a MySQL 5.6 para probar esto (realmente resultó hacer una pequeña diferencia).

El truco básico es crear una tabla de dos filas con valores estáticos (en este caso, 1 y 0 ) usando una UNION y luego LEFT JOIN eso en los resultados reales varias veces para llenar hasta una potencia de 2. Esto significa que hemos calculado el número de cada fila en el resultado (llamado row_num ) para que podamos formular la condición de unión correctamente. Al final, esto produce una fila duplicada cada tantas filas; el bit final es cambiar lo que seleccionamos en esos duplicados (usando IF s) comprobando si estamos en un verdadero o falso (1 o 0 ) fila.

Esto debería evitar que los jugadores del mismo equipo estén uno al lado del otro a menos que esto sea imposible porque un equipo tiene demasiados jugadores; consulte el enlace de arriba para obtener más información sobre cómo hacerlo. La idea básica es ordenar por palo y luego alternar la selección de la primera mitad y la segunda mitad de esa lista.

El truco final fue averiguar cuántos y dónde unirse en las filas ficticias. Después de probar varias cosas, me di cuenta de que esto es realmente muy fácil:simplemente únase con cada fila hasta que hayamos alcanzado el número deseado de filas ficticias (@extra ). Sin embargo, eso empaquetará todas las filas ficticias en la parte superior de los resultados; para distribuirlos más (no perfectamente distribuidos, pero más distribuidos), calcule con qué frecuencia necesitamos agregar uno (FLOOR(@count / @extra) ) y luego coloque una cada tantas filas (la primera parte de ON condición) hasta que se hayan agregado suficientes (la segunda parte).