6

我有一个使用 SQL Server 2008 的表,它有一个表,上面有两个可排序的列,一个是手动设置的,另一个是由系统过程计算的(这个过程将所有内容作为一个整体进行排序,并从 10 开始分配排序,直到最高行数字乘以 10)

ID    Manual     System
------------------------
1      null      300
2      2         380
3      null      500
4      null      200

我试图让它将 id 排序为 4,2,1,3

我希望输出在应用后对系统进行手动排序。如果添加另一行并且它具有也需要考虑的手动排序,则会使事情进一步复杂化。

ID    Manual     System
-----------------------
1      null      300
2      2         380
3      null      500
4      null      200
5      5         100

所以新的排序是 4,2,1,3,5

ID    Manual     System
-----------------------
4      null      200
2      2         380
1      null      300
3      null      200
5      5         100

有任何想法吗?我已经尝试过 Rank、Dense_Rank、Row_Number 等。

对于我的示例,给出的解决方案似乎是正确的。我忘了提到第三列 personID 也是这里的一个因素。

ID    Manual     System    PersonID
-------------------------------------
4      null      200         22
2      2         380         22
1      null      300         22
3      null      200         22
5      5         100         22
8      1         210         25
6      1         480         25
7      null      600         25
9      4         800         25
10     null      990         25

所以我首先必须按人订购,然后按手动订购,然后按分类订购。这似乎仍然给我一个问题。

4

3 回答 3

3

这是我的解决方案:http ://sqlfiddle.com/#!3/a32a0/1/0

SELECT *
FROM
(
  SELECT
    ID
    , ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY System)-.1 AS rn
    , Manual
    , System
    , PersonID
  FROM YourTable
) t0
ORDER BY PersonID
  , COALESCE(Manual, RN)

这是解释:

  • 我们将行号作为基本行号。但是由于我们首先按 PersonID 的高阶索引进行排序,因此在此PARTITION BY...之前我ORDER BY...会重置每个分组的索引MANUAL
  • 在自然排序ROW_NUMBERMANUAL排序之间存在联系的情况下,我减去 0.1((0,1)之间的任意数量)。MANUAL如果出现平局,这将优先考虑该值
  • 在对最终结果进行排序时,我首先ORDER BY是值,首先确保正确分组,然后我按andPARTITION BY的第一个非空值排序MANUALRN

试试看。+指向前两个答案的起点。我以其中一个为起点,然后从那里重新编写。

编辑:删除了 .1 的减法并添加了一个新的排名函数,它“欺骗”优化器更喜欢手动而不是排名。我不知道这是否在所有情况下都成立,或者优化器在其他情况下是否无法按此顺序给出结果,但我想包括这些发现以防万一它们有帮助。

我更新的查询如下:

SELECT *
  FROM
  (
    SELECT
      ID
      , ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY System) AS rn
      , ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Manual) AS rn_throwaway
      , Manual
      , System
      , PersonID
    FROM YourTable
  ) t0
ORDER BY PersonID
  , COALESCE(Manual, RN)

它的使用示例位于http://sqlfiddle.com/#!3/1831d/55/0http://sqlfiddle.com/#!3/a32a0/9/0

于 2013-02-26T15:25:12.167 回答
3

我认为这就是你所需要的。有点难以解释。

Basically inserting not null manual values as row index (or row number) to the record list ordered by system.

小提琴演示

;with cte as (
    select id, manual,system,
           convert(decimal(10,1),row_number() over(order by system)) rn
    from t
    where manual is null 
    union all
    select id, manual,system, convert(decimal(10,1),manual-0.5) rn
    from t
    where manual is not null
)
select id,manual,system
from cte
order by rn


| ID | MANUAL | SYSTEM |
------------------------
|  4 | (null) |    200 |
|  2 |      2 |    380 |
|  1 | (null) |    300 |
|  3 | (null) |    500 |
|  5 |      5 |    100 |
于 2013-02-25T15:57:54.443 回答
3

如果我了解您的要求,您想按 System 列排序,除非提供 Manual 列,在这种情况下,将其用作排序位置?如果是这样,那么这应该适合您使用CASEand ROW_NUMBER

SELECT Id, Manual, System
FROM (
  SELECT Id, 
    Manual, 
    System,
    ROW_NUMBER() OVER (ORDER BY Manual, System)  rn
  FROM YourTable) t
ORDER BY CASE WHEN Manual IS NULL THEN RN ELSE Manual END, COALESCE(Manual,RN+1)

SQL 小提琴演示

于 2013-02-25T16:32:16.533 回答