【问题标题】:Partition By - Sum all values Excluding Maximum Value分区依据 - 对所有值求和,不包括最大值
【发布时间】:2021-09-05 03:01:47
【问题描述】:

我有如下数据

+----+------+--------+
| 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 来应用分区的方法。

【问题讨论】:

  • 对于ID = 2的情况,如果Weight = 350超过2行怎么办?
  • @Squirrel 如果有 2 个以上 Code 为空白/空的,则实际重量为 0。
  • 对不起,我的意思是重量超过 2 行的情况 - 350 并且代码不为空
  • @Squirrel 如果有超过 1 行的最大重量除了 1 包含最大所有其他行将有空白/null Code

标签: sql sql-server group-by partitioning partition-by


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    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
    

    【讨论】:

    • 我收到一个错误Column t.ID is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
    • @洛佩兹。 . .糟糕,忽略了窗框规范。
    • 请从您的回答中查看results。减法似乎不起作用。
    猜你喜欢
    • 2021-02-21
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 2021-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多