【问题标题】:How to write a query with loop in Oracle如何在 Oracle 中编写带循环的查询
【发布时间】:2016-02-22 21:55:52
【问题描述】:

如何编写一个循环执行以下任务的查询: (代入个别结果的id)

    SELECT * From Table where id= 24
    Id | next_to_check  |  next_to_check_2
     24|    34,23       | 4

然后我们检查我们显示的意思是 34,23,4

    SELECT * From tablle where id = 34
    SELECT * From tablle where id = 23
    SELECT * From tablle where id = 4

然后用结果替换结果 34,23,4 然后结果越来越深

24-> 34,23,4
34-> which results in a
23-> which results in a
4-> is as a result of

什么结果 -> 结果与结果等等......

当我手动执行时,它看起来像这样:

【问题讨论】:

  • 你能发布更多细节吗?了解表的确切结构、数据示例和所需结果的示例会很有用
  • 您的桌子似乎设计得很糟糕。您在next_to_check 中有一个复合数据元素,显然next_to_checknext_to_check2 是存储相同值的不同列。如果您将其建模为标准的父子层次表,这将更有意义(并使查询更容易编写)。
  • 他们在我看来你有两个问题:1 你需要将多个值分成单独的行。其次,您需要遍历层次结构。您可以使用table(cast(multiset( 将 , 拆分为多行,然后使用recursive CTEconnect by prior 遍历层次结构

标签: oracle plsql


【解决方案1】:

如果表已正确规范化,查询将非常简单。
正如cmets中提到的,有两个问题:

  • next_to_checknext_to_check2 是存储相同值的两列
  • 两列都包含用逗号分隔的值列表,而不是单个值

表格应如下所示:

SELECT * From Table where id= 24
    Id | next_to_check  | 
     24|    34          | 
     24|    23          |
     24|    4           |

其中next_to_check 列的类型必须与id 列相同,以避免不必要的强制转换。

对于上表,查询可能只是:

SELECT *
FROM "TABLE"
start with id = 24
connect by id = prior next_to_check;

如果无法对表进行规范化,则可以使用如下查询“即时”规范化数据:

WITH normalized_data As (
    SELECT id, trim(regexp_substr(next_to_check, '[^,]+', 1, LEVEL)) next_to_check
    FROM "TABLE"
    CONNECT BY LEVEL <= regexp_count(next_to_check, ',')+1  
    UNION ALL
    SELECT id, trim(regexp_substr(next_to_check_2, '[^,]+', 1, LEVEL)) next_to_check
    FROM "TABLE"
    CONNECT BY LEVEL <= regexp_count(next_to_check_2, ',')+1 
)
SELECT * FROM normalized_data

然后将第一个查询粘合到上面的查询:

WITH normalized_data As (
    SELECT id, trim(regexp_substr(next_to_check, '[^,]+', 1, LEVEL)) next_to_check
    FROM "TABLE"
    CONNECT BY LEVEL <= regexp_count(next_to_check, ',')+1  
    UNION ALL
    SELECT id, trim(regexp_substr(next_to_check_2, '[^,]+', 1, LEVEL)) next_to_check
    FROM "TABLE"
    CONNECT BY LEVEL <= regexp_count(next_to_check_2, ',')+1 
)
SELECT * FROM normalized_data
start with id = 24
connect by id = prior next_to_check;

但是这种“解决方法”的性能会很差,它可能适用于 100 或 1000 条记录,但在更大的表上需要数年时间。

【讨论】:

  • 考虑使用此 REGEXP_SUBSTR() 调用,以便在它们出现时处理 NULL 列表元素:regexp_substr(next_to_check, '(.*?)(,|$)', 1, LEVEL, NULL, 1)。有关更多信息,请参阅此内容,因为使用正则表达式 '[^,]+' 解析具有 NULL 元素的列表会给您带来麻烦:stackoverflow.com/questions/31464275/…。当然,这可能不适用于这种确切的情况,但您最好注意这个问题,以免您在不知情的情况下返回不正确的数据!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-17
  • 1970-01-01
相关资源
最近更新 更多