2013-05-23 2 views
1

J'ai une situation dans laquelle j'essaie d'utiliser une sous-requête corrélée, mais je suis dans la limite d'imbrication dans Oracle. Il se peut que je manque une autre fonctionnalité d'Oracle, alors j'ai pensé que je posterais cette question ici. Est-ce que quelqu'un sait comment réécrire le SQL ci-dessous sans courir dans cette limite d'imbrication, mais aussi rester dans les contraintes ci-dessous?Existe-t-il une solution de contournement à la limite d'imbrication de sous-requêtes corrélées Oracle?

Contraintes:

  • Seul le SQL dans la clause IN peuvent être modifiés (En raison de contraintes indépendantes de ma volonté)
  • Comme le montre, le filtrage dans la requête parent doit être appliqué à la sous-requête d'agrégation avant l'agrégation.
  • Filtre à 0 sur une agrégation des colB après le filtre parent est appliqué

Le code ci-dessous montre mon essai à ce avant de courir dans la limite Oracle. En outre, la version Oracle sur laquelle je suis est 11.2.0.2. Toute aide serait appréciée. Merci!

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 
) 

Voici quelques entrées/sorties d'échantillon de ce que je cherchais lors de l'exécution du SQL ci-dessus:

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 | 

Résultats de SUM sur t3.colB avec t1.colA entre 1 et 2:

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

Résultats de sous-requête pour clause IN avec t1.colA entre 1 et 2:

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

Résultat de la recherche de haut niveau avec t1.colA entre 1 et 2:

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

Après avoir travaillé quelques-unes des réponses fournies, j'ai un moyen d'éviter la limite d'imbrication dans Oracle avec une simple instruction CASE:

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 
) 

Malheureusement, cela a fait surface le vrai problème. Comme il s'agit d'une sous-requête, je ne peux parcourir qu'une seule valeur de la plage t1.colA à la fois. Cela semble rendre impossible l'exécution de la somme analytique dans cette plage dans la sous-requête. Parce que je ne peux que modifier le SQL dans la clause IN, je ne vois pas de solution à ce problème. Si quelqu'un à des suggestions, veuillez s'il vous plait me le faire savoir. Merci.

+0

Que se passe-t-il réellement lorsque vous exécutez cette requête? –

+0

Je reçois l'erreur suivante: ORA-00904: "T1". "COLA" identificateur invalide. – copo24

Répondre

0

Si vous savez ce que les entre valeurs sont et peuvent utiliser ceux de votre sous-requête, vous pouvez ajouter à votre sous-requête à la place:

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

+0

Cela fait partie d'une instruction SQL générée et, malheureusement, ces valeurs changent en fonction d'autres conditions, donc je ne peux pas compter sur elles étant les mêmes. Tout ce que je suis en mesure d'injecter mon SQL dans la clause IN. Merci pour le lien SQL Fiddle si, je ne savais pas sur ce site - très utile. – copo24

0

Vous pouvez réécrire votre requête comme ceci:

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 
    ) 

A partir de là, vous pouvez réécrire comme:

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 
+0

Malheureusement, je ne peux pas réécrire toute la requête. Dans cette situation, je peux seulement changer le segment dans la clause IN. – copo24

Questions connexes