简体   繁体   中英

Sorting a MySQL table with a given ordering and empty random values

I have a MySQL table Section which has a column ordering . Some of the values of ordering are numbers and they are mutually exclusive (no two numbers are the same) and others are simple NULL .

Example:

ID Ordering
-- --------
1  NULL
2  2
3  5
4  NULL
5  NULL
6  3
7  NULL

Now I want to sort this table and get the following result:

(ROW NUMBER) ID  Ordering
------------ --  -------- ------------
1            4   NULL
2            2   2
3            6   3
4            5   NULL
5            3   5
6            7   NULL
7            1   NULL

Ie I want the rows that have a non-NULL value to appear in the given ordering , but the ones that have a NULL value to appear in the remaining ones, in random order (not predictable).

I am sure there are always enough NULL's to fill up the empty spaces.

I was thinking about first getting the ones with an order (WHERE ordering IS NOT NULL) and then the ones without an order (WHERE ordering IS NULL) and then somehow create an extra column that transforms the ones with NULL into a number that doesn't appear in the former.

Any help would be very much appreciated. I am using this in a project where there are sections that have a fixed position, but others can set to have a random order. Every time the page loads the random sections should be displayed, well, randomly.

您可以使用nvl()函数更改非0值的NULL结果

I have found a solution, but it is rather clumsy and big. I'll explain the reasoning:

  • Get a list of numbers from 1 to the number of rows (and call it all_rows ).
  • Get the Sections whose orderings are NOT NULL.
  • Substract those two, ie get from all_rows the ones that are not in the list of already existing orderings and give them a row number. (Call this unused_row_numbers )
  • Get the Sections whose orderings are NULL, randomize them and give them a row number. (Call this nulls_with_row_numbers)
  • Join unused_row_numbers with nulls_with_row_numbers to get all the Sections whose ordering is NULL and now have one of the missing/unused row numbers.
  • Lastly, make the union of this last one with the ones that already have an ordering and tataaaa...

Now here's the SQL:

SELECT row_number, id
FROM (
  SELECT @curRow2 := @curRow2 + 1 AS row_number2, row_number
  FROM (
    SELECT @curRow := @curRow + 1 AS row_number
    FROM Sections
    JOIN (SELECT @curRow := 0) r
  ) all_rows
  JOIN (SELECT @curRow2 := 0) r
  WHERE all_rows.row_number NOT IN (
    SELECT ordering
    FROM Sections
    WHERE ordering IS NOT NULL
  )) unused_row_numbers,
(
  SELECT @curRow3 := @curRow3 + 1 AS row_number3, id
  FROM (
    SELECT ordering, id
    FROM Sections
    WHERE ordering IS NULL
    ORDER BY RAND()
  ) randomized_nulls
  JOIN (SELECT @curRow3 := 0) r
) nulls_with_row_numbers
WHERE unused_row_numbers.row_number2 = nulls_with_row_numbers.row_number3

UNION

SELECT ordering AS row_number, id
FROM Sections
WHERE ordering IS NOT NULL

ORDER BY row_number

It gives different results each time. Example result:

ROW_NUMBER ID
---------- --
1          1  (random)
2          2  (always second position)
3          6  (always third position)
4          4  (random)
5          3  (random)
6          5  (always sixth position)
7          7  (random)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM