【问题标题】:Oracle - Arbitrarily pick one of multiple rows based on single unique keyOracle - 根据单个唯一键任意选择多行之一
【发布时间】:2015-07-16 14:47:36
【问题描述】:

早安!我正在寻找一种技巧来维护可能发生一对多关系的唯一键列表。

问题

我正在使用一个可怕的非规范化数据库,不幸的是,重新设计是不可能的。我有一个 1NF 主表,其中包含许多类似于此的传递和部分键依赖项:

Cmpd_Key  Group  Subgroup   Group_Desc
  A1    |   A   |    1   |    Same
  A2    |   A   |    2   |    Same
  B1    |   B   |    1   |    Same1
  B2    |   B   |    2   |    Same1
  C1    |   C   |    1   |    Diff1
  C2    |   C   |    2   |    Diff2  <---This field contains multiple values

我经常需要提取Group ID 的唯一列表,但要求通常也需要Group_Desc 字段。不幸的是,由于上游数据输入限制不佳,这个描述字段可以包含每个Group 的多个条目,这会导致重复,因为Group 字段在大多数数据拉取中应该是唯一的。出于我的目的,只要我能保持 1 Group 到 1 Group_Desc 的关系,我并不关心我拉哪条 Group_Desc 记录。

我想出了一个丑陋的解决方案,每当我需要在更大的查询中引用 Group_Desc 字段时,我将其称为 Inline View,但这会影响我的性能:

SELECT Group, Group_Desc
FROM Table t
WHERE Subgroup = (SELECT MIN(Subgroup)
                  FROM Table
                  WHERE Group = t.Group) --Nasty Correlated Subquery

问题

有没有人有一个性能友好的技巧来在同一个查询中重复拉回单行的多个值?我希望能够撤回 Group 并且只撤回出现的第一个 Group_Desc

我正在设想这样的事情:

SELECT Group, Group_Desc
FROM Table t
GROUP BY Group, Group_Desc    
HAVING ROWNUM = [The lowest returned Rownum within the same Group]

一位开发人员提到RANK function 是一种可能的解决方案,但我不知道如何使用它来消除值。

您能提供的任何帮助将不胜感激!

----------------编辑----------------------

所以经过一些额外的分析,我能够指出我原来的相关子查询中的一个遗漏,这导致了一个过长的执行计划。通过添加一些额外的谓词,优化器能够创建一个更好的计划,将我的执行时间从大约 12 分钟更改为 2 分钟,这符合我的预期。

我对 Ponder Stibbons 下面建议的分析解决方案做了很多试验。他的解决方案非常优雅,我选择了这个问题的答案,但是,我无法在这个特定的查询中使用它 执行时间比我原来的解决方案慢得多,主要是因为我能够在我的相关子查询中使用一个索引。

我毫不怀疑,在公平的比较中,Analytics 解决方案的运行与 Correlated SubQuery 解决方案相当或更好。感谢大家对这个问题的帮助!

【问题讨论】:

  • order by 子句不能满足您的要求吗?例如stackoverflow.com/questions/11978136/…
  • 我喜欢这个想法,但不幸的是,不,我不能,因为子组编号不一致......为了简单起见,我在这里列出了它,但实际上它可以是各种序列号。

标签: sql oracle group-by duplicates candidate-key


【解决方案1】:

你可以在这里使用解析版的min,速度很快:

select 
    TGroup, 
    min(Group_Desc) over (partition by tgroup) 
  from t

SQLFiddle demo

first_value 也是选项:

select TGroup,
    first_value(Group_Desc) over (partition by tgroup order by subgroup) gd
  from t

【讨论】:

  • 这很有趣。谢谢!我以前没有使用过分析函数,需要了解更多关于它们的信息。我认为这可能是我正在寻找的答案,但我没有得到与您的查询相同的结果集。让我尝试一下这些功能,然后回复您。
  • 是的,查询 2 和你的一样,查询 1 需要 min(group_desc)。因此,对于子组(1 'XYZ',2 'ABC'),首先将始终采用 'ABC',而第二个 - 始终采用 'XYZ'。你可以使用这个更适合你的功能。
  • 好的,所以我发现这确实为我提供了我想要的适当字段值,但它并不能消除重复项。因此,如果我有两个描述并使用 OVER 函数,我会得到正确的值,但我得到了两次......我现在正试图弄清楚如何使用分析函数对结果进行分组。
  • 为了消除重复简单使用distinct。但据我了解,您希望单独显示每一行,但从其他行获取描述,例如在 SQLFiddle 中(无需添加任何带有子查询的级别)。
  • +1 啊.. 太简单了,我简直不敢相信我错过了。我只想完全消除多余的行,以便 Distinct 运行良好。我现在可以重复我原来的设置,但不幸的是它实际上增加了我用来测试性能的查询的执行时间!尽管如此,我仍然喜欢这个解决方案,我将尝试看看我是否可以利用一些索引字段来让它表现更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
  • 2021-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多