为什么不能同时调用两个WITH子句,而又不能调用呢?

时间:2019-03-28 15:25:47

标签: sql oracle common-table-expression

一个简单的实际问题:我有一个表const_a,其中包含大量的行和列。 当我打电话给SELECT A, B, C FROM const_a WHERE restrictive_conditions时,我会得到所有我想处理的行以及唯一需要的列。

行按列A分组,值在列C中,选项在列B中。我的目标是从至少有一行的所有C组中获取所有A的值,其中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的限制不是很严格,并且我不想在restrictive_conditions中重复SELECT DISTINCT,所以我将使用WITH子句,例如:

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')

此查询在合理的时间内起作用,并返回期望值。

最后一个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 Developer客户端都不会给出任何此类指示,只是连接断开。有人有解决方案吗?

这是根据sqlplus命令使用Oracle数据库10g企业版10.2.0.3.0完成的。我已经输入了所有这些内容,因此错误并非来自简单的错字,但感谢您的任何纠正。

编辑:我必须指定,在/*+ MATERIALIZE */子句中的SELECT之后也添加了WITH,它没有什么不同。

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

编辑3:大家好,我找到了解决方案,或者我应该说我找到了问题。 我确实有多个“ C”列,其中之一是CLOB列。我发现奇怪的是,MatBailie的代码在键入时能正常工作,但不是我的,所以我真的尝试通过一点一点地更改MatBailie的查询来构建自己的查询,而当我要求添加其他值列时,它停止工作并尝试添加一个或另一个表明我的CLOB(和我测试过的,与BLOB相同)列太多了。我将不得不使用其他查询。

由于MatBailie是正确的,所以我接受他的解决方案。也感谢APC的帮助,尽管我没有尝试。我觉得这种痕迹可能暗示了正确的解决方案。

1 个答案:

答案 0 :(得分:2)

您的方法应按书面规定工作,请参见此测试:


但是,我认为您可以通过使用解析函数而不是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',它将返回1,否则,它将返回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

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

相关问题