【问题标题】:Oracle SQL Left join same table unknown amount of timesOracle SQL 左连接同一张表的次数未知
【发布时间】:2018-02-26 13:21:49
【问题描述】:

我有这张桌子

| old  | new   | 
|------|-------| 
| a    | b     | 
| b    | c     | 
| d    | e     | 
| ...  | ...   | 
| aa   | bb    | 
| bb   | ff    | 
| ...  | ...   | 
| 11   | 33    | 
| 33   | 523   | 
| 523  | 4444  | 
| 4444 | 21444 | 

我想要达到的结果是

| old  | newest | 
|------|--------| 
| a    | e      | 
| b    | e      | 
| d    | e      | 
| ...  |        | 
| aa   | ff     | 
| bb   | ff     | 
| ...  |        | 
| 11   | 21444  | 
| 33   | 21444  | 
| 523  | 21444  | 
| 4444 | 21444  | 

我可以对查询进行硬编码以获得我想要的结果。

SELECT 
   older.old,
   older.new,
   newer.new firstcol,
   newer1.new secondcol,
   …
   newerX-1.new secondlastcol,
   newerX.new lastcol

from Table older

Left join Table newer 
on older.old = newer.new

Left join Table newer1 
on newer.new = newer1.old

…

Left join Table newerX-1 
on newerX-2.new = newerX-1.old

Left join Table newerX 
on newerX-1.new = newerX.old;

然后只取右边第一个不为空的值。

此处说明:

| old  | new   | firstcol | secondcol | thirdcol | fourthcol |     | lastcol | 
|------|-------|----------|-----------|----------|-----------|-----|---------| 
| a    | b     | c        | e         | null     | null      | ... | null    | 
| b    | c     | e        | null      | null     | null      | ... | null    | 
| d    | e     | null     | null      | null     | null      | ... | null    | 
| ...  | ...   | ...      | ...       | ...      | ...       | ... | null    | 
| aa   | bb    | ff       | null      | null     | null      | ... | null    | 
| bb   | ff    | null     | null      | null     | null      | ... | null    | 
| ...  | ...   | ...      | ...       | ...      | ...       | ... | null    | 
| 11   | 33    | 523      | 4444      | 21444    | null      | ... | null    | 
| 33   | 523   | 4444     | 21444     | null     | null      | ... | null    | 
| 523  | 4444  | 21444    | null      | null     | null      | ... | null    | 
| 4444 | 21444 | null     | null      | null     | null      | ... | null    | 

问题是“替换链”的长度总是在变化(可以从 10 到 100 不等)。

一定有更好的方法来做到这一点?

【问题讨论】:

标签: sql oracle dynamic left-join


【解决方案1】:

您正在寻找的是递归查询。像这样的:

with cte (old, new, lev) as
(
  select old, new, 1 as lev from mytable
  union all
  select m.old, cte.new, cte.lev + 1
  from mytable m
  join cte on cte.old = m.new
)
select old, max(new) keep (dense_rank last order by lev) as new
from cte
group by old
order by old;

递归 CTE 创建所有迭代(您可以通过将查询替换为 select * from cte 来查看这一点)。在最终查询中,我们得到最后一个 new per old 和 Oracle 的 KEEP LAST

Rextester 演示:http://rextester.com/CHTG34988

【讨论】:

  • 收到此错误消息:“ORA-32044:执行递归 WITH 查询时检测到循环”。我觉得你越来越近了。
  • 谢谢!我有一些重复的值吓到了。这确实是正确的。
  • 跟进问题。如果表中有循环,您如何检测它们? Rexter 示例:rextester.com/TBTOX41926
【解决方案2】:

我试图了解您如何对行进行分组以确定不同的“最新”值。这些是您想要基于old 字段的分组吗?

第 1 组 - 一个字母(a、b、d)
第 2 组 - 两个字母 (aa, bb)
第 3 组 - 任意数字(11、33、523、4444)

这是正确的吗?如果是这样,您只需按表达式对它们进行分组,然后使用窗口函数MAX()。像这样的:

SELECT 
  "old",
  MAX() OVER(PARTITION BY MyGrouping) AS newest
FROM (
  SELECT 
    "old",
    CASE 
      WHEN NOT IS_NUMERIC("old") THEN 'string' || CHAR_LENGTH("old") -- If string, group by string length
      ELSE 'number' -- Otherwise, group as a number
    END AS MyGrouping
  FROM MyTable
) src

我不知道 Oracle 是否有 IS_NUMERICCHAR_LENGTH 函数的等价物,所以你需要检查一下。如果不是,则将该表达式替换为类似的内容,如下所示:

https://www.techonthenet.com/oracle/questions/isnumeric.php

【讨论】:

  • 在 Oracle 12.2 中,有一个新函数 validate_conversion 用于检查数据类型 docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/…。 12.2之前没有内置函数。
  • 这与分组无关。示例:如果我说“材料”'b'并且我想知道最新的“材料”?我遵循链“b”->“d”->“e”。如果我说“材料”'33'并且我想知道最新的“材料”?在这种情况下,它是“21444”。
猜你喜欢
  • 2015-02-26
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 2017-07-17
  • 2016-11-27
  • 2021-07-11
  • 1970-01-01
相关资源
最近更新 更多