2009-07-20 7 views
0

Je dois sélectionner des données à partir de deux tables en utilisant une jointure. C'est assez simple et ne pose aucun problème ici. Le problème se produit lorsque le champ que je rejoins est utilisé comme deux clés étrangères distinctes (je ne l'ai pas conçu). Donc, le champ d'identification auquel je participe est soit un nombre positif ou négatif.sql joindre le problème avec des négatifs

S'il s'agit d'un nombre positif, il se rapporte à ID_1 sur la table table_2, s'il s'agit d'un négatif, le nombre se rapporte à ID_2 sur la table table_2. Cependant, l'ID_2 sera un nombre positif (même s'il est enregistré comme négatif dans la clé étrangère). De toute évidence, il n'y a aucune contrainte pour appliquer ces - donc, en substance pas vraies clés étrangères:/

SQL J'utilise quelque chose comme ça va et est très bien pour les nombres positifs:

select t1.Stuff, t2.MoreStuff from table_1 t1 
join table_2 t2 on t1.ID_1 = t2.ID_1 
where ... 

Comment intégrer l'aspect négatif de ceci dans la jointure. Est-ce seulement possible? Idéalement, je voudrais modifier la table à mes besoins, mais apparemment, ce n'est pas une option valable. Je suis bel et bien coincé.

La seule autre idée que j'ai eu est une instruction SQL séparée pour gérer ces étranges. Tout cela est exécuté par clr sql de C#. L'ajout d'une SqlCommand au code ralentira probablement les choses, donc je préférerais tout garder en une seule commande.

Votre contribution est la bienvenue, merci :)

Répondre

2

Disons que les tableaux ressemblent à ceci:

Table1 (id INT, foo INT, fk INT) 

Table2 (id1 INT, id2 INT, bar VARCHAR(100)) 

... où fk peut être utilisé pour rechercher une ligne Table2 utilisant id1 si elle est positive et id2 si elle est négative.

Ensuite, vous pouvez faire la jointure comme suit:

SELECT T1.id, T1.foo, T2.bar 
FROM Table1 T1 INNER JOIN Table2 T2 
ON (T1.fk > 0 AND T2.id1 = T1.fk) 
    OR (T1.fk < 0 AND T2.id2 = - T1.fk) 
+0

il y a un assez long winded où clause évitera l'union mais merci pour l'entrée. Beaucoup de suggestions et je pense que je vais utiliser le vôtre Gary – Tikeb

+0

Merci à tous pour la contribution :) – Tikeb

0

Il devra être quelque chose comme

select t1.Stuff, t2.MoreStuff from table_1 t1, table_2 t2 where (t1.ID_1 = t2.ID_1 OR t1.ID_1 = CONCAT("-",t2.ID_1)) where ... 

Je ne sais pas si je l'ai mal compris votre question.

+1

Qu'est-ce qui vous fait penser que les champs d'identification sont des textes? –

0

En appliquant gauche rejoint sur table à deux et en utilisant la fonction de valeur absolue, vous devriez être en mesure d'accomplir ce que vous cherchez:

SELECT t1.Stuff, isnull(t2.MoreStuff, t2_2.MoreStuff) 
FROM table_1 t1 
    LEFT JOIN table_2 t2  ON t1.ID_1 = t2.ID_1 
          AND t1.ID_1 > 0 
    LEFT JOIN table_2 t2_2 ON abs(t1.ID_2) = t2_2.ID_2 
          AND t1.ID_2 < 0 
WHERE 
    ... 

La mise en garde est que si ID_1 et ID_2 ne sont pas mutuellement En exclusivité, vous obtiendrez 2 résultats de requête.

+0

Assez sûr que cela ne fonctionnera pas. Impossible d'alias deux tables portant le même nom. – Bill

+0

J'ai manqué ça, merci Bill –

2

façon Simpliest - se joindre à ces tables en utilisant UNION ALL:

select t1.Stuff, t2.MoreStuff from table_1 t1 
join table_2 t2 on t1.ID_1 = t2.ID_1 
where t1._ID_1>0 
UNION ALL 
select t1.Stuff, t2.MoreStuff from table_1 t1 
join table_2 t2 on abs(t1.ID_1) = t2.ID_2 
where t1._ID_1<0 
+0

J'ai repoussé ceci et la réponse de Gary McGill. Les deux devraient fonctionner. Je serais intéressé de savoir si la solution UNION est plus rapide ou plus lente que la solution complexe IN clause. – Bill

+0

Je suppose que vous ne voulez pas réellement toutes les lignes dans la table, auquel cas vous aurez besoin d'une clause WHERE. Ce qui rend la méthode UNION un peu pénible, puisque vous devrez dupliquer la partie WHERE. –

+0

D'accord avec Gary, ma solution est plus lente. –

1

Ce ne sera pas très ... mais performant, rien ne va. Vous devez transformer votre clé négative en une clé positive, et une logique conditionnelle pour la jointure. Comme ceci:

select t1.Stuff, t2.MoreStuff 
from table_1 t1 
join table_2 t2 on (t1.ID_1 > 0 AND t1.ID_1 = t2.ID_1) 
    OR (t1.ID_1 <0 AND ABS(t1.ID_1) = t2.ID_2) 
where ... 

Aucune chance d'utiliser un index, parce que vous êtes la transformation t1.ID_1 (avec la fonction ABS), mais il est le meilleur que vous pouvez faire compte tenu des circonstances.

+0

Qu'est-il arrivé à l'instruction CASE? :-) –

+0

Hahaha ... vous m'avez attrapé après avoir posté, et avant que je me rende compte que je n'ai pas utilisé une déclaration de cas du tout ;-) Revised now. –

1

Vous pouvez faire quelque chose comme ça, mais seulement après avoir introduit le concepteur de schéma à un LART:

SELECT 
    t1.stuff, COALESCE(t2a.morestuff, t2b.morestuff) 
    FROM 
    table_1 t1 
    LEFT JOIN table_2 t2a ON (t1.id_1 > 0 AND t1.id_1 = t2a.id_1) 
    LEFT JOIN table_2 t2b ON (t1.id_1 < 0 AND t1.id_1 = -1 * t2b.id_2) 
    // etc 

Alternativement,

SELECT 
    t1.stuff, t2.morestuff 
    FROM 
    table_1 t1 
    LEFT JOIN table_2 t2 ON (
     (t1.id_1 > 0 AND t1.id_1 = t2.id_1) 
     OR (t1.id_1 < 0 AND t1.id_1 = -1 * t2.id_2) 
    ) 
    // etc 

Rappelez-vous le LART, qui est la partie la plus importante!

0
select t1.Stuff, t2.MoreStuff from table_1 t1 
join table_2 t2 on t1.ID_1 = t2.ID_1 or -t1.ID_1 = t2.ID_2 
where ... 
1

essayer cette

DECLARE @Table TABLE(
     ID INT, 
     ForeignKeyID INT 
) 

INSERT INTO @Table (ID,ForeignKeyID) SELECT 1, 1 
INSERT INTO @Table (ID,ForeignKeyID) SELECT 2, 2 
INSERT INTO @Table (ID,ForeignKeyID) SELECT 3, -1 
INSERT INTO @Table (ID,ForeignKeyID) SELECT 4, -2 

DECLARE @ForeignTable TABLE(
     ID_1 INT, 
     ID_2 INT, 
     Val VARCHAR(MAX) 
) 

INSERT INTO @ForeignTable (ID_1,ID_2,Val) SELECT 1, 11, '1' 
INSERT INTO @ForeignTable (ID_1,ID_2,Val) SELECT 2, 22, '2' 
INSERT INTO @ForeignTable (ID_1,ID_2,Val) SELECT 3, 1, '3' 
INSERT INTO @ForeignTable (ID_1,ID_2,Val) SELECT 3, 2, '4' 

SELECT * 
FROM @Table t INNER JOIN 
     @ForeignTable ft ON ABS(t.ForeignKeyID) = 
          CASE 
           WHEN t.ForeignKeyID > 0 
            THEN ft.ID_1 
           ELSE 
            ft.ID_2 
          END 
Questions connexes