为什么调用两个 WITH 子句,一个调用另一个,不起作用?

Why do calling two WITH clauses, with one calling the other, not work?

简单的实际问题:我有一个 table、const_a,其中包含大量的行和列。 当我调用 SELECT A, B, C FROM const_a WHERE restrictive_conditions 时,我获得了我希望处理的所有行和我需要的唯一列。

行按 A 列分组,值在 C 列中,选项在 B 列中。我的目标是从所有 A 组中获取所有 C 值,这些组至少有一行 B 具有特定值,比方说 'v'.

第一个查询将是:

SELECT C FROM const_a
WHERE restrictive_conditions
AND A IN (SELECT DISTINCT A FROM const_a WHERE B LIKE 'v')

B LIKE 'v'const_a 的限制不是很大,我不想在 SELECT DISTINCT 中重复 restrictive_conditions,所以我将使用 [=26] =] 子句,像这样:

WITH tmp_a AS (SELECT A, B, C FROM const_a WHERE restrictive_conditions)
SELECT C FROM tmp_a
WHERE A IN (SELECT DISTINCT A FROM tmp_a WHERE B LIKE 'v')

此查询在合理的时间内有效,并且 returns 预期值。

最后一个SELECT DISTINCT在查询的上下文中比较晦涩,所以为了便于理解,我添加了第二个WITH:

WITH tmp_a AS (SELECT A, B, C, FROM const_a WHERE restrictive_conditions),
tmp_b AS (SELECT DISTINCT A FROM tmp_a WHERE B LIKE 'v')
SELECT C FROM tmp_a WHERE A IN (SELECT A FROM tmp_b) ;

我给 tmp_atmp_b 取了有意义的名字,这里它类似于 minimal_rangevalid_groups,收工了,但是当我尝试运行 这个查询我不断收到断开连接错误,根据我的搜索表明 Oracle 在后台自行崩溃,没有告诉我。

我已经尝试并测试了所有的别名方式,使用 INNER JOIN 而不是 WHERE ... IN ...,但没有成功;当我有两个或多个 WITH 子句时,一个调用另一个,然后我将它们一起调用,它会崩溃。根据我构建它的方式,我也得到了空结果(尽管独立尝试不同的部分给出了预期的结果,就好像 WITH 子句在被另一个子句调用后自行清空)。这不是期望的结果。

在这种情况下,我可以使用不同的查询,但我想知道如何一起使用嵌套的 WITH 子句。其他人也可能从中受益。

有人可以解释为什么这不起作用吗?我希望这是一个简单的语法错误,但控制台和 Oracle SQL 开发人员客户端都没有给出任何此类指示,只是连接丢失。有人有解决办法吗?

根据 sqlplus 命令,这是使用 Oracle 数据库 10g 企业版 10.2.0.3.0 版完成的。我已经输入了所有内容,所以错误不是简单的打字错误,但感谢您的任何更正。

编辑:我必须说明,我还在我的 WITH 子句中的 SELECT 之后添加了 /*+ MATERIALIZE */,它没有做任何不同的事情。

编辑 2:没关系,我以为我找到了空子句。

Edit 3 : 大家好,我找到了解决办法,或者说我找到了问题所在。 我确实有多个“C”列,其中之一是 CLOB 列。我发现很奇怪,当我输入 MatBailie 的代码时它起作用了,但我的却不起作用,所以我真的试着通过一点一点地改变他的代码来重建我自己的查询,当我要求额外的值列时,它停止工作,并试图添加一个或另一个表明我的 CLOB(我测试过,与 BLOB 相同)列太多了。我将不得不使用不同的查询。

既然 MatBailie 是正确的,我就接受他的解决方案。也感谢 APC 的帮助,尽管我没有尝试过。我有一种感觉,跟踪会暗示正确的解决方案。

你的方法应该像写的那样有效,请看这个测试:


不过,我认为您可以通过使用解析函数而不是 IN()...

来简化计算过程
WITH
  restrict_and_check AS
(
  SELECT
    A, B, C,
    MAX(CASE WHEN B = 'v' THEN 1 ELSE 0 END)
      OVER (
        PARTITION BY A
      )
        AS a_includes_b_that_equals_v
  FROM
    const_a
  WHERE
    restrictive_condition
)
SELECT
  C
FROM
  restrict_and_check
WHERE
  a_includes_b_that_equals_v = 1

MAX() OVER ()就像一个子查询,带有聚合函数。

在上面的示例中,它按列 A 对数据进行分区,并将具有相同值的所有行传递给函数。

本例中的函数是 MAX(CASE WHEN B = 'v' THEN 1 ELSE 0 END),如果任何传入行具有 B = 'v',它将 return 为 1,否则它将 return 0.

有点像...

SELECT
  *
FROM
  a_data_set
INNER JOIN
(
  SELECT
    A,
    MAX(CASE WHEN B = 'v' THEN 1 ELSE 0 END) AS a_includes_b_that_equals_v
  FROM
    a_data_set
  GROUP BY
    A
)
  a_check
    ON a_check.A = a_data_set.A

要获得更清晰的解释,请查看解析函数或窗口函数。