Mới và cải tiến (cách sử dụng phiên bản 3) bằng cách sử dụng các biến và về cơ bản sử dụng cùng một thủ thuật từ tại đây :
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
Đối với dữ liệu ví dụ bạn đã cung cấp, điều này tạo ra một cái gì đó giống như:
+--------------+-----------+
| 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 |
+--------------+-----------+
Điều này sẽ hoạt động cho bất kỳ kết quả kích thước nào; chỉ cần thay đổi điều kiện (y_of_birth = 2000
) thành bất kỳ điều kiện nào bạn muốn. Tôi đã nâng cấp lên MySQL 5.6 để kiểm tra điều này (nó thực sự tạo ra một sự khác biệt nhỏ).
Thủ thuật cơ bản là tạo một bảng hai hàng với các giá trị tĩnh (trong trường hợp này là 1
và 0
) sử dụng UNION
và sau đó LEFT JOIN
điều đó vào kết quả thực tế một số lần để lấp đầy đến lũy thừa 2. Điều này có nghĩa là chúng tôi đã tính toán số lượng của mỗi hàng trong kết quả (được gọi là row_num
) để chúng ta có thể xây dựng điều kiện nối một cách chính xác. Cuối cùng, điều này tạo ra một hàng trùng lặp cứ sau rất nhiều hàng; bit cuối cùng là thay đổi những gì chúng tôi chọn trên các bản sao đó (sử dụng IF
s) bằng cách kiểm tra xem chúng tôi đang sử dụng hàng thật hay giả (1
hoặc 0
) hàng.
Điều này sẽ ngăn những người chơi trong cùng một đội ở cạnh nhau trừ khi điều này là không thể vì một đội có quá nhiều người chơi; xem liên kết ở trên để biết thêm về cách thực hiện điều đó. Ý tưởng cơ bản là đặt hàng theo câu lạc bộ và sau đó chọn luân phiên từ nửa đầu và nửa sau của danh sách đó.
Bí quyết cuối cùng là tìm ra số lượng và vị trí để tham gia vào các hàng giả. Sau khi thử một số cách, tôi nhận ra rằng điều này thực sự rất dễ dàng:chỉ cần kết hợp với mọi hàng cho đến khi chúng tôi đạt được số lượng hàng giả mong muốn (@extra
). Tuy nhiên, điều đó sẽ đóng gói tất cả các hàng giả ở đầu kết quả; để trải rộng chúng ra nhiều hơn (không phải dàn trải hoàn hảo mà là trải rộng hơn), hãy tính tần suất chúng ta cần thêm một (FLOOR(@count / @extra)
) và sau đó đặt một trong nhiều hàng như vậy (phần đầu tiên của ON
điều kiện) cho đến khi đã thêm đủ (phần thứ hai).