在不破坏顺序的情况下对列进行分组
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 中前一行的值,然后使用窗口化COUNT
将ROW_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 或 PARTITION BY 的情况下对 Oracle SQL 中的数据进行分组
Mysql:如何在不丢失组内个人行的情况下对组进行排序[关闭]