2009-12-15 19 views
2

Mon problème est sur Oracle, mais est probablement indépendant de la base de données (?).Comment éviter l'union par jointure?

Je les tableaux suivants:

aa

vid cb 
--- -- 
    1 10 
    2 15 

bb

vid cb 
--- -- 
    3 25 
    4 24 

** représentant *

repid vid p 
----- --- -- 
    99 1 aa 
    99 2 aa 
    99 3 bb 
    99 4 bb 

La colonne p indique dans quelle table obtenir la ligne. En réalité, aa et bb sont beaucoup plus différents, et p ne correspond pas au nom de la table, mais donne un moyen d'y arriver. L'exemple est juste une simplification où j'ai un problème. Notez qu'en réalité, il y a plus de 2 tables aa et bb (il y en a 6). Je veux une requête qui retourne ceci:

repid vid p cb 
----- --- -- -- 
    99 1 aa 10 
    99 2 aa 15 
    99 3 bb 25 
    99 4 bb 24 

Les travaux suivants: (a)

select rep.vid, rep.p, cb 
from (
select 'aa' as p,vid,cb from aa 
union all 
select 'bb' as p, vid,cb from bb) u,rep 
where rep.p=u.p and rep.vid=u.vid 

(b)

select rep.vid, rep.p, 
    decode(rep.p, 'aa', (select cb from aa where vid=rep.vid), 
       'bb', (select cb from bb where vid=rep.vid)) cb 
from rep 

Mais je voudrais utiliser la requête dans une vue, sur laquelle il peut y avoir un prédicat poussant.

Donc la question 1 est: est-ce que ce qui suit permet de pousser les prédicats. Question 2: (même si oui pour la question 1) existe-t-il un moyen de le faire sans union, mais avec des jointures. Question 3: Ou tout simplement, une meilleure façon?

script pour créer les données:

create table bb (vid number(1), cb number(2)); 
create table aa (vid number(1), cb number(2)); 
create table rep(rid number(2), vid number(1), p varchar2(2)); 
insert into rep (rid,vid,p) values (99, 4,'bb'); 
insert into rep (rid,vid,p) values (99, 3,'bb'); 
insert into rep (rid,vid,p) values (99, 2,'aa'); 
insert into rep (rid,vid,p) values (99, 1,'aa'); 
insert into bb (vid,cb) values (4,24); 
insert into bb (vid,cb) values (3,25); 
insert into aa (vid,cb) values (2,15); 
insert into aa (vid,cb) values (1,10); 
commit; 
+0

Avez-vous le contrôle du schéma? Je suppose que vous ne pouvez pas changer l'une des tables? – Burt

+0

Correct: les tables existent déjà, et je ne peux pas les changer. –

Répondre

0

A join pouvez spécifier plusieurs conditions. Le nom de la table peut être un. Par exemple, si table1 a une colonne appelée TableName qui fait référence à d'autres tables, vous pouvez utiliser:

select  * 
from  table1 t1 
left join table2 t2 
on   t1.TableName = 'table2' 
      and t1.id = t2.id 
left join table3 t3 
on   t1.TableName = 'table3' 
      and t1.id = t3.id 

Vous pouvez ajouter un nombre arbitraire de tables de cette façon.

Pour votre troisième question, il y a toujours une meilleure solution. La question est, est-ce que cela suffit? Si non, pouvez-vous définir les exigences pour une solution acceptable?

+0

Oui, si les tables avaient une colonne appelée tableName, cela aiderait certainement. Le problème est qu'ils ne le font pas. Je suppose qu'une solution serait de créer des vues autour de ces tables et d'inclure le nom de table (ou équivalent). –

+0

@Nicolas: Votre table "rep" contient un champ "pp" avec le nom de table? – Andomar

+0

En fait, qu'auriez-vous à la place du * pour avoir la colonne cb de table1, ou cb de table2 en fonction de la valeur de p. Ceci est une grande partie du problème: "fusion" les colonnes de différentes tables. –

2

Je n'ai plus d'instance Oracle à ma disposition, mais j'ai essayé des choses avec PostgreSQL, ce qui pourrait être intéressant de toute façon?

Mon expérience avec PostgreSQL suggère que l'union fonctionne mieux. J'ai créé une vue basée sur votre requête d'union, et postgres était capable de pousser un prédicat tel que "cb entre 12 et 27" dans les scans de aa et bb.

Par constraste, je crée une vue qui utilise rejoint:

create view rep2 as 
    select rep.vid, p, coalesce(aa.cb, bb.cb) as cb 
    from rep 
     left join aa on aa.vid = rep.vid and rep.p = 'aa' 
     left join bb on bb.vid = rep.vid and rep.p = 'bb' 

Le problème est maintenant que les blocs soudent() un prédicat impliquant cb poussé dans les scans de aa et bb.