在不破坏顺序的情况下对列进行分组

Posted

技术标签:

【中文标题】在不破坏顺序的情况下对列进行分组【英文标题】:Grouping Column Without Breaking The Sequence 【发布时间】:2020-11-18 05:31:40 【问题描述】:

主要目的是将金额列后面的行按顺序分组,这样如果两个相同的值之间有任何不同的值,它们将分别编号。 这是这里的原始数据:

SELECT Area, DateA, DateB, Amount
FROM (VALUES
    ('ABC', '2019-08-18', '2019-08-18 00:07:47.000', 3.75),
    ('ABC','2019-08-19', '2019-08-19 00:08:47.000', 3.75),
    ('ABC','2019-08-20', '2019-08-20 00:09:47.000', 3.65),
    ('ABC','2019-08-21', '2019-08-21 00:09:57.000', 3.75))
    AS FeeCollection(Area, DateA, DateB, Amount)

我试过这个,但我不知道用特殊方式编号的真正问题。

DENSE_RANK() OVER(ORDER BY Area, Amount)

这是我想要实现的示例结果。我正在寻找简单的逻辑来做到这一点。使用 cursor 或 while 循环对我来说效率不高。

【问题讨论】:

我不在电脑前,但我认为您需要:OVER (PARTITION BY DateA ORDER BY area, amount) @AlanBurstein 在使用 DateA 列进行分区时聚合函数可能会给出一些不相关的值。但我很欣赏这种方法。 是的 - 我猜。很高兴你把这个整理好了。 【参考方案1】:

我相信这就是你想要的。我使用LAG 获取CTE 中前一行的值,然后使用窗口化COUNTROW_NUMBER 的值每行减少1,amount 具有相同的连续值:

WITH CTE AS(
    SELECT Area,
           DateA,
           DateB,
           Amount,
           LAG(Amount) OVER (PARTITION BY Area ORDER BY DateA) AS PrevAmount
    FROM (VALUES
        ('ABC', '2019-08-18', '2019-08-18 00:07:47.000', 3.75),
        ('ABC','2019-08-19', '2019-08-19 00:08:47.000', 3.75),
        ('ABC','2019-08-20', '2019-08-20 00:09:47.000', 3.65),
        ('ABC','2019-08-21', '2019-08-21 00:09:57.000', 3.75))
        AS FeeCollection(Area, DateA, DateB, Amount))
SELECT Area,
       DateA,
       DateB,
       Amount,
       ROW_NUMBER() OVER (PARTITION BY Area ORDER BY DateA) - 
       COUNT(CASE Amount WHEN PrevAmount THEN 1 END) OVER (PARTITION BY Area ORDER BY DateA
                                                           ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Number
FROM CTE
ORDER BY DateA;

我确实假设了您的 PARTITION BY 子句,您可能需要更改/删除/移动到 ORDER BY。因为我们只有一个 Area 的值,所以我们不可能知道当它发生变化时应该是什么值。

【讨论】:

面积列并非所有值都相同,但此方法确实可以正确区分。【参考方案2】:

我会使用 lag() 和累积总和来执行此操作,但看起来像:

select t.*,
       sum(case when prev_amount = amount then 0 else 1 end) over
           (partition by area order by datea) as number
from (select t.*,
             lag(amount) over (partition by area order by datea) as prev_amount
      from t
     ) t;

【讨论】:

以上是关于在不破坏顺序的情况下对列进行分组的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 GROUP BY 子句的情况下对行进行分组

如何在不使用 GROUP BY 或 PARTITION BY 的情况下对 Oracle SQL 中的数据进行分组

Mysql:如何在不丢失组内个人行的情况下对组进行排序[关闭]

Movilizer:在不更改数组键的情况下对数据容器进行排序

我可以在没有递归和堆栈的情况下对二叉树进行顺序遍历吗?

在不知道学生人数和每个学生课程数量的情况下对学生的平均成绩排序