按多列排序,忽略 Null
Order by multiple columns, ignoring Null
我有一个视图,它显示了某个项目到达多个位置的时间。我想按到达时间排序此视图:
ITEM | At Loc1 | At Loc2 | At Loc3 | At Loc4 | Desired Order
--------------------------------------------------------
aaa | 00:00 | 02:01 | NULL | 05:30 | 0
bbb | NULL | 02:30 | 06:21 | NULL | 1
ccc | 00:05 | 02:33 | NULL | 07:10 | 2
ddd | 00:07 | NULL | 06:25 | 09:00 | 3
eee | NULL | NULL | 06:30 | 09:10 | 4
fff | 00:30 | 02:55 | 06:32 | NULL | 5
有时由于测量错误或不规则而没有记录到达时间。在这种情况下,时间是 NULL
现在我要Select * from View ORDER BY AtLoc1 ASC, AtLoc2 ASC, AtLoc3 ASC, AtLoc4 ASC
但是列中的 Null 值不应导致项目转到前面或后面。根据下一列,它应该保持在正确的相对位置。
比如项目bbb在位置1没有被记录,但是它在aaa之后ccc之前到达了位置2,所以它应该在aaa和ccc之间排序,而不是在列表的开头或结尾
在大多数情况下,项目不会在不同位置之间更改顺序,但这并非不可能。
我不认为我可以为所有特殊情况定义一个唯一且定义明确的排序顺序,当有太多 NULL 聚集在一起时,该顺序可能未定义。但我只想介绍 null 值相对稀疏的最常见情况。
如何用这种方式对SQL中的视图进行排序?
需要更多测试,但试试这个:
WITH cte as (
SELECT *,
CASE WHEN [At Loc1] IS NOT NULL
THEN row_number() over (order by [At Loc1] )
END as r1,
CASE WHEN [At Loc2] IS NOT NULL
THEN row_number() over (order by [At Loc2] )
END as r2,
CASE WHEN [At Loc3] IS NOT NULL
THEN row_number() over (order by [At Loc3] )
END as r3,
CASE WHEN [At Loc4] IS NOT NULL
THEN row_number() over (order by [At Loc4] )
END as r4
FROM Table1
)
SELECT *, COALESCE(r1,r2,r3,r4)
FROM cte
ORDER BY COALESCE(r1,r2,r3,r4),
COALESCE(r2,r3,r4),
COALESCE(r3,r4),
r4
;
输出
不,你无法得到稳定的排序,因为你可能有这样的东西:
aaa 1 7
bbb NULL 6
ccc 2 5
基本上,这三件事是正确的:
- ccc > aaa
- bbb > ccc
- aaa > bbb
这些不能同时全部为真(至少对于我们通常使用的数字或时间而言)。
Juan Carlos 提供了一个非常好的临时解决方案,但并非在所有情况下都有效。
我有一个视图,它显示了某个项目到达多个位置的时间。我想按到达时间排序此视图:
ITEM | At Loc1 | At Loc2 | At Loc3 | At Loc4 | Desired Order
--------------------------------------------------------
aaa | 00:00 | 02:01 | NULL | 05:30 | 0
bbb | NULL | 02:30 | 06:21 | NULL | 1
ccc | 00:05 | 02:33 | NULL | 07:10 | 2
ddd | 00:07 | NULL | 06:25 | 09:00 | 3
eee | NULL | NULL | 06:30 | 09:10 | 4
fff | 00:30 | 02:55 | 06:32 | NULL | 5
有时由于测量错误或不规则而没有记录到达时间。在这种情况下,时间是 NULL
现在我要Select * from View ORDER BY AtLoc1 ASC, AtLoc2 ASC, AtLoc3 ASC, AtLoc4 ASC
但是列中的 Null 值不应导致项目转到前面或后面。根据下一列,它应该保持在正确的相对位置。
比如项目bbb在位置1没有被记录,但是它在aaa之后ccc之前到达了位置2,所以它应该在aaa和ccc之间排序,而不是在列表的开头或结尾
在大多数情况下,项目不会在不同位置之间更改顺序,但这并非不可能。
我不认为我可以为所有特殊情况定义一个唯一且定义明确的排序顺序,当有太多 NULL 聚集在一起时,该顺序可能未定义。但我只想介绍 null 值相对稀疏的最常见情况。
如何用这种方式对SQL中的视图进行排序?
需要更多测试,但试试这个:
WITH cte as (
SELECT *,
CASE WHEN [At Loc1] IS NOT NULL
THEN row_number() over (order by [At Loc1] )
END as r1,
CASE WHEN [At Loc2] IS NOT NULL
THEN row_number() over (order by [At Loc2] )
END as r2,
CASE WHEN [At Loc3] IS NOT NULL
THEN row_number() over (order by [At Loc3] )
END as r3,
CASE WHEN [At Loc4] IS NOT NULL
THEN row_number() over (order by [At Loc4] )
END as r4
FROM Table1
)
SELECT *, COALESCE(r1,r2,r3,r4)
FROM cte
ORDER BY COALESCE(r1,r2,r3,r4),
COALESCE(r2,r3,r4),
COALESCE(r3,r4),
r4
;
输出
不,你无法得到稳定的排序,因为你可能有这样的东西:
aaa 1 7
bbb NULL 6
ccc 2 5
基本上,这三件事是正确的:
- ccc > aaa
- bbb > ccc
- aaa > bbb
这些不能同时全部为真(至少对于我们通常使用的数字或时间而言)。
Juan Carlos 提供了一个非常好的临时解决方案,但并非在所有情况下都有效。