2009-08-05 7 views
1

Voici le code pour vous aider à comprendre ma question:Comment éviter de répéter une sous-requête CORRELATED?

create table con (content_id number); 
create table mat (material_id number, content_id number, resolution number, file_location varchar2(50), file_size number); 
create table con_groups (content_group_id number, content_id number); 

insert into con values (99); 
insert into mat values (1, 99, 7, 'C:\foo.jpg', 1024); 
insert into mat values (2, 99, 2, '\\server\xyz.mov', 350000); 
insert into mat values (3, 99, 5, '\\server2\xyz.wav', 175000); 
insert into con values (100); 
insert into mat values (4, 100, 5, 'C:\bar.png', 2048); 
insert into mat values (5, 100, 3, '\\server\xyz.mov', 27400); 
insert into mat values (6, 100, 7, '\\server2\xyz.wav', 400); 

insert into con_groups values (10, 99); 
insert into con_groups values (10, 100); 

SELECT m.material_id, 
     m.content_id, 
     (SELECT max(file_location) keep (dense_rank first order by resolution desc)     
      FROM mat 
     WHERE mat.content_id = m.content_id 
     /* AND ... 
      AND ... 
      AND ... */) special_mat_file_location, 
     (SELECT max(file_size) keep (dense_rank first order by resolution desc) 
      FROM mat 
     WHERE mat.content_id = m.content_id 
     /* AND ... 
      AND ... 
      AND ... */) special_mat_file_size 
    FROM mat m 
WHERE m.material_id IN (select material_id 
          from mat 
        inner join con on con.content_id = mat.content_id 
        inner join con_groups on con_groups.content_id = con.content_id 
          where con_groups.content_group_id = 10); 

je mets les ANDs commentaires pour mettre en évidence que c'est un exemple simplifié; la sous-requête dans ma requête réelle est plus complexe avec plus de critères.

Mon problème est: Je veux éviter de répéter tous les critères de la sous-requête pour les deux colonnes (file_location and file_size) car le critère est exactement le même. J'utiliserais avec plaisir les expressions de table communes (c'est-à-dire la factorisation de sous-requête en utilisant la clause WITH) mais je ne peux pas en raison du "WHERE mat.content_id = m.content_id" dans la sous-requête, ce qui en fait une sous-requête corrélée. Je crois comprendre qu'on ne peut pas factoriser les sous-requêtes corrélées en utilisant la clause WITH. Pour la même raison, je ne peux pas non plus mettre cette sous-requête en tant que vue en ligne (ou table dérivée) dans la clause FROM.

Comment puis-je inclure les critères une fois et injecter plus d'une colonne dans le jeu de résultats avec une sous-requête corrélée?

+0

S'agit-il simplement de taille de texte de requête ou de performances de requête qui vous inquiètent? – jva

+0

C'est une bonne question. Je suis inquiet de maintenir cette requête plus tard, si les critères de la sous-requête changent (ce qui est une réelle possibilité). Donc, oui, je m'inquiète de la taille du texte de la requête. –

Répondre

1

Utilisez l'affacturage de sous-requête (c'est ce que Oracle appelle - il s'agit d'une expression de table commune dans SQL Server). 9i + pris en charge:

WITH file AS (
    SELECT t.content_id, 
     MAX(t.file_location) keep (DENSE_RANK t.first ORDER BY t.resolution DESC) 'fileLocation', 
     MAX(t.file_size) keep (DENSE_RANK t.first ORDER BY t.resolution DESC) 'fileSize' 
    FROM mat t 
GROUP BY t.content_id) 
SELECT m.material_id, 
     m.content_id, 
     f.fileLocation, 
     f.fileSize 
    FROM mat m 
    JOIN file f ON f.content_id = m.content_id 

Il est destiné à être réutilisé en vue en ligne. Vous généraliser la vue et définir un filtrage spécifique pour différentes instances dans la clause JOIN. Vous devez exposer les colonnes à joindre dans la clause SELECT - voir le content_id à titre d'exemple. Une sous-requête corrélée signifie qu'elle peut être réécrite en tant que JOIN - la corrélation est le critère JOIN.

Vous pouvez définir plusieurs vues dans la sous-requête Affacturage - si vous fournissiez plus de détails, je pourrais mieux adapter la réponse.

+0

Quelqu'un peut-il expliquer pourquoi c'est mieux que la simple jointure dans la clause FROM? Ou même en mettant la logique de sous-requête dans une vue séparée? – jva

+0

Re: "Une sous-requête corrélée signifie qu'elle peut être réécrite en tant que JOIN" - C'est une pensée intéressante. Je vais avoir un peu de mal avec votre requête si. Il a dit que le fichier était un nom de table invalide, donc je l'ai renommé. Ensuite, il n'a pas aimé comment les colonnes agrégées ont été nommées, donc j'ai changé cela. Maintenant, je reçois le message "ORA-00937: pas une fonction de groupe à groupe unique" pour content_id. Suis-je totalement malentendu quelque chose? –

+0

@jva: Google "affacturage sous-requête". –

0

Je pense que je l'ai eu. Je suis en mesure de saisir simplement la clé primaire de la matière « spéciale » et envelopper la requête principale dans une autre couche, comme ceci:

  SELECT x.material_id, 
       x.content_id, 
       sp_m.file_location, 
       sp_m.file_size 
      FROM (SELECT m.material_id, 
         m.content_id, 
         (SELECT max(material_id) keep (dense_rank first order by resolution desc)     
          FROM mat 
          WHERE mat.content_id = m.content_id 
         /* AND ... 
          AND ... 
          AND ... */) special_mat_primary_key 
        FROM mat m 
        WHERE m.material_id IN (select material_id 
              from mat 
             inner join con on con.content_id = mat.content_id 
             inner join con_groups on con_groups.content_id = con.content_id 
              where con_groups.content_group_id = 10)) x 
LEFT OUTER JOIN mat sp_m ON sp_m.material_id = x.special_mat_primary_key; 

Laissez-moi savoir ce que vous pensez.

+0

Un sous-élément corrélé signifie qu'il s'exécutera pour chaque ligne renvoyée. La clause IN est la manière la moins performante d'interroger les choses. Vous créez une vue en ligne avec plus d'informations que nécessaire. –

Questions connexes