分区依据 - 对不包括最大值的所有值求和

Partition By - Sum all values Excluding Maximum Value

我有数据如下

+----+------+--------+
| ID | Code | Weight |
+----+------+--------+
|  1 | M    |    200 |
|  1 | 2A   |     50 |
|  1 | 2B   |     50 |
|  2 |      |    350 |
|  2 | M    |    350 |
|  2 | 3A   |    120 |
|  2 | 3B   |    120 |
|  3 | 5A   |    100 |
|  4 |      |    200 |
|  4 |      |    100 |
+----+------+--------+

对于 ID 1,最大权重是 200,我想从 ID 1 中减去所有权重的总和,除了最大值 200

可能有 2 行包含同一 ID 的最大值的情况。对于 ID 2 的示例,我们有 2 行包含最大值,即 350 。在这种情况下,我想对除最大值以外的所有值求和。但我会为包含最大值的 2 行中的 1 行标记权重 0。该行将是 Code 是 NULL/Blank.

的那一行

如果 ID 只有 1 行,则该行将保持原样。

另一种情况可能是只有一行包含最大权重,但 Code 是 NULL/Blank,在这种情况下,我们将简单地执行我们为 ID 1 所做的操作。对除最大值以外的所有值求和并从包含最大值的行中减去。

期望输出

+----+------+--------+---------------+
| ID | Code | Weight | Actual Weight |
+----+------+--------+---------------+
|  1 | M    |    200 |           100 |
|  1 | 2A   |     50 |            50 |
|  1 | 2B   |     50 |            50 |
|  2 |      |    350 |             0 |
|  2 | M    |    350 |           110 |
|  2 | 3A   |    120 |           120 |
|  2 | 3B   |    120 |           120 |
|  3 | 5A   |    100 |           100 |
|  4 |      |    200 |           100 |
|  4 |      |    100 |           100 |
+----+------+--------+---------------+

我想创建列 Actual Weight,如上所示。我找不到通过排除最大值和创建列 Actual Weight.

来应用分区的方法

嗯。 . .我认为您只需要 window 函数和条件逻辑:

select t.*,
       (case when 1 = row_number() over (partition by id order by weight desc, (case when code <> '' then 2 else 1 end))
             then weight - sum(case when weight <> max_weight then weight else 0 end) over (partition by id)
             else weight
        end) as actual_weight
from (select t.*,
             max(weight) over (partition by id, code) as max_weight
      from t
     ) t

dense_rank() 标识最大权重的行,dr = 1 是最大权重的行

row_number() 区分 Code = blank 的最大重量行与其他行


with cte as
(
    select *, 
           dr = dense_rank() over (partition by ID order by [Weight] desc),
           rn = row_number() over (partition by ID order by [Weight] desc, Code desc)
    from   tbl
)
select *,
       ActWeight = case when dr = 1 and rn <> 1
                        then 0
                        when dr = 1 and rn = 1
                        then [Weight]
                           - sum(case when dr <> 1 then [Weight] else 0 end) over (partition by ID)
                        else [Weight]
                        end
from   cte

dbfiddle demo