2009-08-24 4 views
2

J'ai deux tables TABLE_A et TABLE_B ayant la colonne jointe comme numéro d'employé EMPNO.SQL joint gauche gauche avec seulement quelques lignes de la droite?

Je souhaite effectuer une jointure externe gauche normale. Cependant, TABLE_B a certains enregistrements qui sont supprimés (status='D'), je veux que ceux-ci soient inclus. Juste pour clarifier, TABLE_B pourrait avoir des enregistrements actifs (status = null/a/quoi que ce soit) ainsi que des enregistrements supprimés, dans ce cas, je ne veux pas cet employé dans mon résultat. Si toutefois il n'y a que des enregistrements supprimés de l'employé dans TABLE_B je veux que l'employé soit inclus dans le résultat. J'espère que je fais mon exigence claire. (Je pourrais faire un long truc de qrslt et obtenir ce que je veux, mais je pense qu'il doit y avoir une façon plus optimisée de le faire en utilisant la syntaxe join). Apprécierait toutes les suggestions (même sans la jointure). Son newbness essaye la requête suivante sans le résultat désiré:

SELECT TABLE_A.EMPNO 
FROM TABLE_A 
LEFT OUTER JOIN TABLE_B ON TABLE_A.EMPNO = TABLE_B.EMPNO AND TABLE_B.STATUS<>'D' 

Beaucoup apprécient n'importe quelle aide.

Répondre

0

ah crud, cela fonctionne apparemment> <

SELECT TABLE_A.EMPNO 
FROM TABLE_A 
LEFT OUTER JOIN TABLE_B ON TABLE_A.EMPNO = TABLE_B.EMPNO 
where TABLE_B.STATUS<>'D' 

Si vous les gars avez des informations supplémentaires à sonner avec cependant, s'il vous plaît ne hésitez pas.

MISE À JOUR: Saw cette question après un certain temps et pensé que je vais ajouter des informations utiles: Ce lien a une bonne information concernant la syntaxe ANSI - http://www.oracle-base.com/articles/9i/ANSIISOSQLSupport.php

En particulier cette partie de la page liée est informative:

Des conditions de filtre supplémentaires peuvent être ajoutées à la jointure en utilisant AND pour former une jointure complexe. Ils sont souvent nécessaires lorsque des conditions de filtre sont requises pour restreindre une jointure externe. Si ces conditions de filtre sont placées dans la clause WHERE et que la jointure externe renvoie une valeur NULL pour la colonne de filtre, la ligne sera rejetée. Si la condition du filtre est codée dans le cadre de la jointure, la situation peut être évitée.

+0

Cela ne remplit pas l'obligation d'inclure les lignes où le * employé seulement * a supprimé les enregistrements, n'est-ce pas? – Eric

+0

En fait, c'est le cas. L'employé a seulement supprimé les enregistrements dans TAble_b (mais a une ligne dans TABLE_A). Ok, je dois vérifier à nouveau quand je serai au bureau. –

0

La requête suivante vous obtiendra les enregistrements d'employés qui ne sont pas supprimés, ou seulement l'employé a seulement des enregistrements supprimés.

select 
    a.* 
from 
    table_a a 
    left join table_b b on 
     a.empno = b.empno 
where 
    b.status <> 'D' 
    or (b.status = 'D' and 
     (select count(distinct status) from table_b where empno = a.empno) = 1) 

C'est dans la norme ANSI SQL, mais si je savais SGBDR, je pourrais donner une solution plus spécifique qui peut être un peu plus élégant.

+0

Devrait avoir mentionné cela, j'utilise oracle 10g. Eric, une clarification concernant cette condition. où b.status <> 'D' puisqu'il s'agit d'une jointure gauche par rapport à une jointure externe gauche, cela n'inclut-il pas réellement les lignes qui ne sont pas supprimées? ou (b.status = 'D' et (sélectionnez le compte (état distinct) de table_b où empno = a.empno) = 1) je reçois cela, il n'y a que des enregistrements supprimés dans table_b, donc cet emp est inclus . –

2

Juste pour clarifier - tous les enregistrements de TABLE_A devraient apparaître, sauf s'il y a des lignes dans le tableau B avec des statues autres que que 'D'?

Vous aurez besoin d'au moins une colonne non nulle sur B (je vais utiliser « B.ID » comme un exemple, et cette approche devrait fonctionner):

SELECT TABLE_A.EMPNO 
FROM TABLE_A 
LEFT OUTER JOIN TABLE_B ON 
    (TABLE_A.EMPNO = TABLE_B.EMPNO) 
    AND (TABLE_B.STATUS <> 'D' OR TABLE_B.STATUS IS NULL) 
WHERE 
    TABLE_B.ID IS NULL 

C'est, inverser la logique que vous pourriez penser - joindre sur TABLE_B seulement où vous avez des lignes qui excluent TABLE_A entrées, puis utilisez l'IS NULL à la fin pour les exclure. Cela signifie que seuls ceux qui ne correspondent pas (ceux qui n'ont pas de ligne dans TABLE_B, ou avec seulement les lignes 'D') sont inclus.

Une alternative pourrait être

SELECT TABLE_A.EMPNO 
FROM TABLE_A 
WHERE NOT EXISTS (
    SELECT * FROM TABLE_B 
    WHERE TABLE_B.EMPNO = TABLE_A.EMPNO 
    AND (TABLE_B.STATUS <> 'D' OR TABLE_B.STATUS IS NULL) 
) 
+0

En fait, je veux que les lignes avec le statut 'd' soient incluses dans la jointure. Je ne veux pas d'autre statut à inclure. Idée étant je veux que les lignes de la gauche ou TABLE_A qui ne sont pas dans table_b. Une ligne de table_b étant supprimée en mode soft implique qu'elle n'existe pas du tout et ne devrait pas être exclue de ma requête. (J'espère que vous lisez, vous répondez à droite) –

0
SELECT A.*, B.* 
FROM 
    Table_A A 
    INNER JOIN Table_B B 
     ON A.EmpNo = B.EmpNo 
WHERE 
    NOT EXISTS (
     SELECT * 
     FROM Table_B X 
     WHERE 
      A.EmpNo = X.EmpNo 
      AND X.Status <> 'D' 
    ) 

Je pense que cela fait l'affaire. La jointure à gauche n'est pas nécessaire car vous souhaitez uniquement inclure les employés avec toutes les lignes supprimées (et au moins une).

0

Voici comment je comprends la question. Vous devez inclure uniquement les employés dont l'une des conditions suivantes est remplie:

  • un employé a seulement (Soft-) lignes supprimées dans TABLE_B; Un salarié n'a que des lignes non supprimées dans TABLE_B; Un salarié n'a aucune ligne dans TABLE_B.

En d'autres termes, si un employé a la fois supprimé et les lignes non supprimées dans TABLE_B, omettez cet employé, sinon les inclure.

Voilà comment je pense que cela pourrait être résolu:

SELECT DISTINCT a.EMPNO 
FROM TABLE_A a 
    LEFT JOIN TABLE_B b1 ON a.EMPNO = b1.EMPNO 
    LEFT JOIN TABLE_B b2 ON b1.EMPNO = b2.EMPNO 
    AND (b1.STATUS = 'D' AND (b2.STATUS <> 'D' OR b2 IS NULL) OR 
     b2.STATUS = 'D' AND (b1.STATUS <> 'D' OR b1 IS NULL)) 
WHERE b2.EMPNO /* or whatever non-nullable column there is */ IS NULL 

Sinon, cependant, vous pouvez utiliser groupement:

SELECT a.EMPNO 
FROM TABLE_A a 
    LEFT JOIN TABLE_B b ON a.EMPNO = b1.EMPNO 
GROUP BY a.EMPNO 
HAVING 0 IN (COUNT(CASE b.STATUS WHEN 'D' THEN 1 ELSE NULL END), 
      COUNT(CASE b.STATUS WHEN 'D' THEN NULL ELSE 1 END)) 
Questions connexes