Oracle SQL:使用带有递归 CTE 的 SELECT INTO 时出现“缺少关键字”

Posted

技术标签:

【中文标题】Oracle SQL:使用带有递归 CTE 的 SELECT INTO 时出现“缺少关键字”【英文标题】:Oracle SQL: "missing keyword" when using SELECT INTO with a recursive CTE 【发布时间】:2018-01-18 11:09:24 【问题描述】:

在存储过程中,我试图根据通过 WITH 和递归 CTE 语句创建的虚拟数据集来设置声明的 varchar(100) 变量“my_path”的值。

首先我尝试“SELECT INTO”,但出现“缺少关键字”错误。

我也可以考虑从 WITH 语句中更新值为 'path' 的表行,但随后出现“缺少选择关键字”错误,并且我了解到我无法在 Oracle SQL Server 中使用 CTE 进行更新。但是有什么方法可以访问递归 CTE 的输出呢?我稍后在我的存储过程中需要它。

declare mypath varchar(100);
begin
with CTE (toN,path,done)
as
(
-- anchor
select
cap.toN,
concat(concat(CAST(cap.fromN as varchar(10)) , ',') , CAST(cap.toN as varchar(10))),
case when cap.toN = 10000 then 1 else 0 end
from cap 
where
(fromN = 1) and (cap.cap_up > 0)

union all
-- recursive
select
cap.toN, 
concat(concat(path,','), CAST(cap.toN as varchar(10)) ),
case when cap.toN=10000 then 1 else 0 end
from cap join cte on 
cap.fromN = cte.toN
where
(cap.cap_up > 0) and (cte.done = 0)
)
select path into mypath from cte where done=1
);
end;

【问题讨论】:

使用 CTE 时,一个语句可能会引用先前的语句。但是您的陈述是在引用自己 - 不确定这是否合法。 FROM 是 Oracle 中的关键字 - 您不应在关键字之后命名列,但如果必须,您需要将它们括在双引号中(并确保使用正确的大小写)(即 @ 987654323@). @ChristianPalmer 这是一个 recursive 子查询分解子句 - 它是合法的。 @user1777530 : 我认为问题是最后的')' 在声明部分在mypath varchar(100)之后添加分号。 【参考方案1】:

我认为您的代码应该可以工作。它确实有一个挥之不去的结束括号,这是可疑的。

也许一些简化会有所帮助:

with CTE(toN, path, done) as (
-- anchor
      select cap.toN, cap.fromN || ',' || cap.toN 
             (case when cap.toN = 10000 then 1 else 0 end)
     from cap 
     where fromN = 1 and cap.cap_up > 0
     union all
     -- recursive
     select cap.toN, path || ',' || cap.toN,
            (case when cap.to = 10000 then 1 else 0 end)
     from cap join
          cte 
          on cap.fromN = cte.toN
     where cap.cap_up > 0 and cte.done = 0
    )
select path into my_path
from cte
where done = 1;

【讨论】:

CTE 没有toN 列,因此连接将失败。【参考方案2】:

现在您已经修复了变量名称...您仍然需要 CTE 的第三列来包含 toN,它位于查询的递归部分的连接条件中。在查询的末尾还有一个尾随 ) 括号,您可以使用 || 连接字符串(您不需要将其转换为 varchars)。

WITH CTE (path,done, toN) as (
  -- anchor
  SELECT fromN || ',' || toN,
         CASE WHEN toN = 10000 THEN 1 ELSE 0 END,
         toN
  FROM   cap 
  WHERE  "FROM" = 1
  AND    cap_up > 0
UNION ALL
  -- recursive
  SELECT cte.path || ',' || cap.toN,
         CASE WHEN cap.toN =10000 THEN 1 ELSE 0 END,
         cap.toN
  FROM   cap
         join cte
         on   ( cap.fromN = cte.toN )
  WHERE  cap.cap_up > 0
  AND    cte.done = 0)
)
select path into my_path from cte where done=1;

更简单的解决方案是使用分层查询。

SELECT SUBSTR( SYS_CONNECT_BY_PATH( fromN, ',' ), 2 ) || ',' || toN
INTO   mypath
FROM   cap
WHERE  toN = 10000
START WITH fromN = 1
CONNECT BY PRIOR toN = fromN;

【讨论】:

以上是关于Oracle SQL:使用带有递归 CTE 的 SELECT INTO 时出现“缺少关键字”的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server CTE 递归查询全解

Presto SQL 是不是像 SQL Server 一样支持使用 CTE 进行递归查询?例如员工等级

sql server使用cte递归查询获取树形的父节点/子节点

sql递归cte在视图中不能正常工作

SQL 中with的用法

T-SQL使用CTE递归