1

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

约束:

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

下面的代码显示了我在遇到 Oracle 限制之前的尝试。另外,我使用的 Oracle 版本是 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  |

t3.colB 与 t1.colA 在 1 和 2 之间的 SUM 结果:

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

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

---------
| 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,所以我看不到这个问题的解决方案。如果有人有任何建议,请告诉我。谢谢。

4

2 回答 2

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 小提琴演示

于 2013-05-24T00:39:05.707 回答
0

You can rewrite your query like this:

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
      )

From here, you can rewrite it as:

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 
于 2013-05-24T03:01:04.257 回答