【问题标题】:Merging rows in SQL (Oracle)在 SQL (Oracle) 中合并行
【发布时间】:2016-02-24 13:40:29
【问题描述】:

我希望在我的表(我们称之为 MY_TABLE)上运行 UPDATE 和随后的 DELETE 查询,以下列方式合并所有行。

输入表

ID  LowerRange  UpperRange  Attribute
1   10          20          A
2   20          30          A
3   40          50          A
4   15          35          B

输出表

ID  LowerRange  UpperRange  Attribute
1   10          30          A
3   40          50          A
4   15          35          B

注意如何...

  1. 输入表的第 1 行和第 2 行合并到输出表的第 1 行,因为它们的范围重叠并且具有相同的属性。
  2. 输入表的第 3 行未与第 1 行和第 2 行合并,因为它们的范围不重叠,尽管它们具有相同的属性。
  3. 输入表的第 4 行未与第 1 行和第 2 行合并,因为它们没有相同的属性,尽管有重叠的范围。

TABLE 中的所有行将在它们的范围重叠且具有相同属性的地方合并。

如果您有任何问题,请告诉我。任何帮助将不胜感激。

谢谢, 斯蒂芬。

【问题讨论】:

  • 您是否会遇到下一行与同一属性的上一行重叠的情况?例如。对于属性 C,(lower_range, upper_range) 为 (10, 20) 和 (15, 23) 的行。或者,lower_range 是否总是与前一行的 upper_range 相同或更大?

标签: sql oracle merge


【解决方案1】:

这是一种方法(假设您可能有重叠的行,其中当前行的开始范围小于或等于前一行的结束范围):

with sample_data as (select 1 id, 10 lower_range, 20 upper_range, 'A' attribute from dual union all
                     select 2 id, 20 lower_range, 30 upper_range, 'A' attribute from dual union all
                     select 3 id, 40 lower_range, 50 upper_range, 'A' attribute from dual union all
                     select 4 id, 15 lower_range, 35 upper_range, 'B' attribute from dual union all
                     select 5 id, 45 lower_range, 55 upper_range, 'A' attribute from dual union all
                     select 6 id, 16 lower_range, 34 upper_range, 'B' attribute from dual)
select min(id) id,
       min(lower_range) lower_range,
       max(upper_range) upper_range,
       attribute
from   (select id,
               lower_range,
               upper_range,
               attribute,
               sum(diff) over (partition by attribute order by lower_range, upper_range) grp
        from   (select id,
                       lower_range,
                       upper_range,
                       attribute,
                       case when lag(upper_range, 1, lower_range) over (partition by attribute order by lower_range, upper_range) >= lower_range then 0 else 1 end diff
                from   sample_data))
group by attribute, grp;

        ID LOWER_RANGE UPPER_RANGE ATTRIBUTE
---------- ----------- ----------- ---------
         1          10          30 A        
         3          40          55 A        
         4          15          35 B        

如果您的行仅在前一个 upper_range 与当前 lower_range 相同时重叠,则只需从 case 语句中删除 >

它的作用是查看当前行的 lower_range 是否大于或等于前一行的 upper_range。如果是,那么我们将结果设置为0,否则我们将其设置为1(表示两行之间有间隙)。

接下来,我们对每个属性的所有行执行累积求和。然后,对于重叠的行,这将具有相同的结果,并且每次遇到间隙时都会增加 1。

现在我们可以将它与属性列一起使用来对行进行分组,并找到它们的最小/最大范围以及 min(id)。

【讨论】:

  • 是的,您的假设是正确的,即如果一行的下限小于或等于另一行,则如果一行的上限大于或等于另一行,则该行与另一行重叠。这似乎正是我想要的,非常感谢你到目前为止的帮助。在我将此标记为已接受的答案之前剩下的唯一一件事............我将如何为我的表“MY_TABLE”中的所有行执行初始“使用样本数据作为”部分?
  • 您不需要 sample_data 子查询;您将在主 SQL 语句中使用您的表。我只创建了 sample_data 子查询来模拟一个包含数据的表,以便我可以测试查询是否有效。
  • 啊,是的,我几分钟前刚刚尝试过,发现它有效。非常感谢。在我的表上运行查询后,我注意到只有一点点不同,我在原始帖子中没有明确说明。假设两行都具有相同的属性,并且一行的上限为 9,而另一行的上限为 10。这些也应该合并。我认为这是通过使其 >= MSISDN_LOWER-1 来完成的,但您可能需要确认?
  • 这两行的 lower_range 是多少?
  • 是的,>= lower_range - 1 应该适合您的目的。
【解决方案2】:

【讨论】:

  • 抱歉,也许我应该明确表示:以上只是一个简化的示例。我的表实际上包含数千行,其中包含许多不同的 LowerRanges、UpperRanges 和 Attributes。但我想要做的是整张桌子都是一样的。
  • lowerrange 的数据类型是什么。看起来它是文本,因为值之间有一个空格......等待你的答案也许在你可以拆分值之后,case 语句会起作用。 CASE WHEN Col BETWEEN col1 AND col2 THEN X ELSE 'NOTHING' END AS UpperRange
  • 这个问题前面已经回答过了。查看我编辑的答案中的链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-20
  • 1970-01-01
  • 2022-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多