按两列对 MySQL 结果进行排序,但其中一列是“有空隙”的。

huangapple go评论50阅读模式
英文:

Sort mysql result by two column, but with a “holed” column

问题

我有以下的初始情况:

  +------------+-------------+
  | legacyRank | forcedRank  |
  +------------+-------------+
  | 0          | NULL        |
  | 1          | 6           |
  | 2          | NULL        |
  | 3          | 1           |
  | 4          | NULL        |
  | 5          | NULL        |
  | 6          | 2           |
  +------------+-------------+

你可以通过以下模式生成这个表格:

CREATE TABLE two_column_order (
  legacyRank VARCHAR(45),
  forcedRank VARCHAR(45)
);

INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (5, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (6, 2); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (7, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (0, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (1, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (2, 6); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (3, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (4, 1); 


SELECT * FROM two_column_order
order by
  CASE when `forcedRank`  <> NULL THEN `forcedRank`
  ELSE `legacyRank`
  END

目标是将每一行中没有NULL的forcedRank列放在forcedRank列中指定的准确位置。期望的结果如下:

  +------------+-------------+
  | legacyRank | forcedRank  |
0 | 0          | NULL        |
1 | 3          | 1           |
2 | 6          | 2           |
3 | 2          | NULL        |
4 | 4          | NULL        |
5 | 5          | NULL        |
6 | 6          | 6           |
  +------------+-------------+

如你所见,如果forcedRank列不是NULL,每一行都按照forcedRank列的顺序排列。当NULL行仍然按照legacyRank列在非NULL行未占用的位置上排序,但不会移动强制行。

在这个顺序中,我尝试在ORDER BY中使用CASE WHEN语法,如下:

SELECT * FROM two_column_order

order by 
  CASE WHEN (`forcedRank` is NULL )  THEN `legacyRank`
  END ,

  -`forcedRank` DESC,
  `legacyRank`

但结果并不符合我的期望:

+------------+-------------+
| legacyRank | forcedRank  |
+------------+-------------+
| 3          | 1           |
| 6          | 2           |
| 6          | 6           |
| 0          | NULL        |
| 2          | NULL        |
| 4          | NULL        |
| 5          | NULL        |
+------------+-------------+

那么,如何使legacyRank列在不移动强制行的情况下获得顺序?

英文:

I have the following initial situation:

  +------------+-------------+
  | legacyRank | forcedRank  |
  +------------+-------------+
  | 0          | NULL        |
  | 1          | 6           |
  | 2          | NULL        |
  | 3          | 1           |
  | 4          | NULL        |
  | 5          | NULL        |
  | 6          | 2           |
  +------------+-------------+

You could generate this table by the following schema:

CREATE TABLE two_column_order (
  legacyRank VARCHAR(45),
  forcedRank VARCHAR(45)
);

INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (5, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (6, 2); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (7, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (0, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (1, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (2, 6); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (3, NULL); 
INSERT INTO two_column_order (legacyRank, forcedRank)
VALUES (4, 1); 


SELECT * FROM two_column_order
order by
  CASE when `forcedRank`  <> NULL THEN `forcedRank`
  ELSE `legacyRank`
  END

The goal is to put each line with no-NULL forcedRank column in the accurate position mentioned in this forcedRank column. The expected rendering is like:

  +------------+-------------+
  | legacyRank | forcedRank  |
  +------------+-------------+
0 | 0          | NULL        |
1 | 3          | 1           |
2 | 6          | 2           |
3 | 2          | NULL        |
4 | 4          | NULL        |
5 | 5          | NULL        |
6 | 6          | 6           |
  +------------+-------------+

As you see, each line take the position ordered by the forcedRank column if not NULL. When the the NULL rows still sorted by the legacyRank column in the positions leaved unoccupied by the non-NULL rows, but never shift the forced rows.

In this order, I tried to use the CASE WHEN syntax inside the ORDER BY like this:

SELECT * FROM two_column_order

order by 
  CASE WHEN (`forcedRank` is NULL )  THEN `legacyRank`
  END ,

  -`forcedRank` DESC,
  `legacyRank`

But the result doesn’t really feat my expectations:

+------------+-------------+
| legacyRank | forcedRank  |
+------------+-------------+
| 3          | 1           |
| 6          | 2           |
| 6          | 6           |
| 0          | NULL        |
| 2          | NULL        |
| 4          | NULL        |
| 5          | NULL        |
+------------+-------------+

So how can I make the legacyRank column get order beyond the forcedrank rows without shift them?

答案1

得分: 1

NULL 不能像这样进行比较,您需要使用 IS 或在您的情况下使用 IS NOT

SELECT * FROM two_column_order
order by
  CASE when `forcedRank` IS NOT NULL THEN `forcedRank`
  ELSE `legacyRank`
  END
legacyRank forcedRank
0 null
1 null
4 1
6 2
3 null
5 null
2 6
7 null

fiddle

由于第一个答案不会给出正确的答案。

我通过在原始数字中添加一个小数点来更改排序,使其大于新的强制排名。这将保持顺序,如果强制编号小于传统排名,它将为您提供以下结果。

SELECT * FROM two_column_order
order by
  CASE when `forcedRank` IS NOT NULL THEN `forcedRank` 
  ELSE `legacyRank` + .1
  END
legacyRank forcedRank
0 null
4 1
1 null
6 2
3 null
5 null
2 6
7 null

fiddle

英文:

NULL can't tbe comapred like that you need to use ISor in your case IS NOT

SELECT * FROM two_column_order
order by
  CASE when `forcedRank`  IS NOT NULL THEN `forcedRank`
  ELSE `legacyRank`
  END
legacyRank forcedRank
0 null
1 null
4 1
6 2
3 null
5 null
2 6
7 null

fiddle

As the first answer won't give you the correct answer.

i have changed the order by adding a decimal point to the original number so that it will be bigger than the new forced rank.

it will keep the order and a the forced number is smaller then the legayrank, it get you follwoing result

SELECT * FROM two_column_order
order by
  CASE when `forcedRank`  IS NOT NULL THEN `forcedRank` 
  ELSE `legacyRank` + .1
  END
legacyRank forcedRank
0 null
4 1
1 null
6 2
3 null
5 null
2 6
7 null

fiddle

huangapple
  • 本文由 发表于 2023年2月19日 23:29:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/75501216.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定