Oracle Correlated Subquery Nesting Limit是否有解决方法?

时间:2013-05-23 23:28:34

标签: sql oracle subquery correlated-subquery in-subquery

我遇到的情况是我试图使用相关的子查询,但是我遇到了Oracle中的嵌套限制。我可能会错过Oracle的另一个功能,所以我想我会在这里发布这个问题。有没有人知道如何在不遇到这个嵌套限制的情况下重写下面的SQL,但是还要保持在下面的约束范围内?

约束:

  • 只能修改IN子句中的SQL (由于我无法控制的限制)
  • 如图所示,在聚合发生之前,需要将父查询中的过滤应用于聚合子查询。
  • 在应用父过滤器后,在colB聚合上过滤掉0

以下代码显示了我在尝试此操作之前遇到的Oracle限制。此外,Oracle版本I是11.2.0.2。任何帮助,将不胜感激。谢谢!

SELECT
  *
FROM
  table1 t1
WHERE
  t1.colA BETWEEN XXXX AND XXXX 
  AND t1.pk_id IN (
    SELECT
      t2.pk_id
    FROM (
      SELECT
        t3.pk_id,
        SUM(t3.amt) OVER (PARTITION BY t3.colB) amt
      FROM table1 t3
        WHERE t3.colA = t1.colA
    ) t2
    WHERE
      t2.amt <> 0
  )

以下是运行上述SQL时我正在寻找的一些示例输入/输出:

Sample table1:
-----------------------------
| pk_id | colA | colB | amt |
-----------------------------
|   1   |  1   |  A   |  2  |
|   2   |  1   |  A   |  -1 |
|   3   |  1   |  B   |  1  |
|   4   |  2   |  B   |  1  |
|   5   |  2   |  A   |  -2 |
|   6   |  2   |  A   |  1  |
|   7   |  3   |  A   |  1  |

使用t1.colA BETWEEN 1和2时的SUM与t3.colB的结果:

---------------
| pk_id | amt |
---------------
|   1   |  0  |
|   2   |  0  |
|   3   |  2  |
|   4   |  2  |
|   5   |  0  |
|   6   |  0  |    

IN子句的子查询结果,带有t1.colA BETWEEN 1和2:

---------
| pk_id |
--------- 
|   3   |
|   4   |

使用t1.colA BETWEEN 1和2的顶级查询结果:

-----------------------------
| pk_id | colA | colB | amt |
-----------------------------
|   3   |  1   |  B   |  1  |
|   4   |  2   |  B   |  1  |

在完成所提供的一些答案之后,我有一种方法可以通过一个简单的CASE语句来避免Oracle中的嵌套限制:

SELECT
  *
FROM
  table1 t1
WHERE
  t1.colA BETWEEN 1 AND 2
  AND t1.pk_id IN (
    SELECT
      CASE
        WHEN SUM(t2.amt) OVER (PARTITION BY t2.colB) <> 0 THEN t2.pk_id
        ELSE NULL
      END
    FROM table1 t2
    WHERE t2.colA = t1.colA
  )

不幸的是,这表明了真正的问题。因为这是一个子查询,所以我一次只能遍历t1.colA范围的一个值。这似乎使得无法在子查询中执行该范围内的分析总和。因为我只能修改IN子句中的SQL,所以我看不到这个问题的解决方案。如果有人有任何建议,请告诉我。感谢。

2 个答案:

答案 0 :(得分:0)

如果您知道值之间的内容并且可以在子查询中使用它们,那么您可以将其添加到子查询中:

SELECT
    *
FROM
    table1 t1
WHERE
    t1.colA BETWEEN 1 AND 2
    AND t1.pk_id IN (
        SELECT
            t2.pk_id
        FROM 
            (
                SELECT
                    t3.pk_id,
                    SUM(t3.amt) OVER (PARTITION BY t3.colB) amt
                FROM table1 t3
                WHERE t3.colA BETWEEN 1 AND 2
            ) t2
        WHERE
            t2.amt <> 0
    )

SQL Fiddle Demo

答案 1 :(得分:0)

您可以像这样重写您的查询:

SELECT *
FROM table1 t1
WHERE t1.colA BETWEEN XXXX AND XXXX and
      t1.pk_id IN (
        SELECT t2.pk_id
        FROM (SELECT t3.pk_id, t3.ColA, SUM(t3.amt) as amt
              FROM table1 t3
              group by t3.pk_id, t3.ColA
              having sum(t3.amt) > 0
             ) t2
        WHERE t2.colA = t1.colA
      )

从这里开始,您可以将其重写为:

select t1.*
from table1 t1 join
     (SELECT t3.pk_id, t3.ColA, SUM(t3.amt) as amt
      FROM table1 t3
      group by t3.pk_id, t3.ColA
      having sum(t3.amt) > 0
     ) t2
     on t1.pk_id = t2.pk_id and t1.ColA = t3.ColA
WHERE t1.colA BETWEEN XXXX AND XXXX