如何按值分组,但前提是它们是连续的?

问题描述 投票:0回答:1

我有下表:

ID 数字 尺码
7 1 1.5
7 2 1.5
8 1 1.625
8 2 1.03125
8 3 1.03125
8 4 1.03125
8 5 1.625
8 6 1
8 7 1.625
8 8 1.625
8 9 1.625
9 1 1
9 2 2
9 3 3
9 4 4
9 5 1

我想为每个 ID 创建一个包含单个字符串值的列,用于对尺寸进行分组,但前提是这些值基于数字是连续的,并且包括匹配尺寸的数量。

例如,对于ID=8,我想要这样的东西:

1.625 x 1.03125 (x3) x 1.625 x 1 x 1.625 (x3)

请注意,数字可以增加到任何整数值,大小可以是任何正数,最多 7 位小数。

正如我一直在思考的那样,这些是我到目前为止考虑的步骤:

  1. 当连续值相等时,将尺寸分组。我考虑过使用 LAG()/LEAD() 函数来完成这个或 CASE 表达式。也许也可以执行一些 GROUP BY/子查询魔法来实现这一点?无论如何,此步骤将返回类似这样的内容,其中“组”列是可用于对同一 ID 内的值进行分组的任何内容:
ID 数字 尺码 团体
7 1 1.5 1
7 2 1.5 1
8 1 1.625 1
8 2 1.03125 2
8 3 1.03125 2
8 4 1.03125 2
8 5 1.625 3
8 6 1 4
8 7 1.625 5
8 8 1.625 5
8 9 1.625 5
9 1 1 1
9 2 2 2
9 3 3 3
9 4 4 4
9 5 1 5
  1. 然后,一旦我创建了一个合适的组列,我想接下来我将对尺寸进行分组并为该组中的数量创建一个额外的列。这看起来像这样:
ID 数字 尺码 团体 数量
7 1 1.5 1 2
8 1 1.625 1 1
8 2 1.03125 2 3
8 5 1.625 3 1
8 6 1 4 1
8 7 1.625 5 3
9 1 1 1 1
9 2 2 2 1
9 3 3 3 1
9 4 4 4 1
9 5 1 5 1

最后,可能会结合使用 STRING_AGG() 和 CONCAT() 函数,我会将数据放入以下格式:

ID 尺码
7 1.5 (x2)
8 1.625 (x1) x 1.03125 (x3) x 1.625 (x1) x 1 (x1) x 1.625 (x3)
9 1 (x1) x 2 (x1) x 3 (x1) x 4 (x1) x 1 (x1)

而且,我最好省略“(x1)”,这样最终的形式如下所示:

ID 尺码
7 1.5 (x2)
8 1.625 x 1.03125 (x3) x 1.625 x 1 x 1.625 (x3)
9 1×2×3×4×1

有点多。但最后,我希望将这些表中的数据转换为用户更易读的格式,但是 1) 我不确定如何做到这一点,以及 2) 鉴于可能有多种途径来实现这一点,我不确定性能最高的选项是什么。

有什么想法吗?

附言我对任何方法都持开放态度,它当然不必遵循我在此处包含的思路。

*编辑添加新数据集(ID=9)

sql-server group-by case gaps-and-islands string-aggregation
1个回答
1
投票

你有一个gaps and islands problem,一种选择是使用两个

row_number
之间的差异来定义所需的组,使用SQL Server语法尝试以下操作:

with cte1 as -- Step 1: using the difference between two row_numbers approach, create groups for consecutive similar values of Size.
(
  select *,
   row_number() over (partition by id order by number) - 
   row_number() over (partition by id, size order by number) grp
  from table_name 
),
cte2 as -- Step 2: get the counts for each group defined in the previous step
(
  select id, min(number) number, size, grp, count(*) cnt
  from cte1
  group by id, size, grp
)
  -- Step 3: use string_agg and concat functions to get the desired format
select id, 
  string_agg
    (-- use a case expression to not include (1x) when count = 1
      case when cnt > 1 then concat(size, ' (x', cnt, ')') else cast(size as varchar(20)) end, ' x '
    ) within group (order by number) Size
from cte2
group by id
order by id

看演示

© www.soinside.com 2019 - 2024. All rights reserved.