Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

SQL - imprime muitas palavras entre todas as colunas com muitas condições


Novo e aprimorado (versão 3 como) usando variáveis ​​e usando basicamente o mesmo truque aqui :
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 os dados de exemplo que você forneceu, isso produz 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 |
+--------------+-----------+

Isso deve funcionar para qualquer resultado de tamanho; basta alterar a condição (y_of_birth = 2000 ) para ser qualquer condição que você quiser. Atualizei para o MySQL 5.6 para testar isso (na verdade, acabou fazendo uma pequena diferença).

O truque básico é criar uma tabela de duas linhas com valores estáticos (neste caso, 1 e 0 ) usando um UNION e então LEFT JOIN isso nos resultados reais algumas vezes para preencher até uma potência de 2. Isso significa que calculamos o número de cada linha no resultado (chamado row_num ) para que possamos formular a condição de junção corretamente. No final, isso produz uma linha duplicada a cada tantas linhas; a parte final é alterar o que selecionamos nessas duplicatas (usando IF s) verificando se estamos em uma versão real ou falsa (1 ou 0 ) fileira.

Isso deve evitar que jogadores do mesmo time fiquem próximos uns dos outros, a menos que isso seja impossível porque um time tem muitos jogadores; veja o link acima para saber mais sobre como fazer isso. A ideia básica é ordenar por clube e depois alternar entre a primeira e a segunda metade dessa lista.

O truque final foi descobrir quantos e onde juntar nas filas fictícias. Depois de tentar várias coisas, percebi que isso é realmente muito fácil:basta juntar todas as linhas até atingirmos o número desejado de linhas fictícias (@extra ). No entanto, isso empacotará todas as linhas fictícias na parte superior dos resultados; para espalhá-los mais (não perfeitamente espalhados, mas mais espalhados), calcule com que frequência precisamos adicionar um (FLOOR(@count / @extra) ) e, em seguida, coloque uma a cada tantas linhas (a primeira parte do ON condição) até que o suficiente tenha sido adicionado (a segunda parte).