2009-08-19 10 views
2

Peut-être que je vais dans le mauvais sens. Voici ce que j'essaie de faire et mon problème.Rejoindre une table deux fois dans une deuxième table avec chaque alias interne joint aux deux alias d'une troisième table

J'ai 3 tables. actifs (un ordinateur, un appareil de réseau, etc.) ports (un port sur l'ordinateur, périphérique réseau, etc.) port_connections (a un champ port_id_a et port_id_b et des liens chaque port et à cet effet chaque actif ensemble)

Il est vraiment juste un moyen de suivre VLAN et les périphériques réseau/ordinateurs dans les immeubles de bureaux. J'utilise la dernière version de Firebird en utilisant le dialecte 3. Je suppose que ce n'est pas un problème de Firebird et juste un problème avec mon SQL.

Je sais que cela doit être possible parce que je peux le faire avec juste des jointures correctes (ports à port_connections) et faire les autres jointures dans la clause WHERE. Le problème avec ceci est que les jointures correctes sont perdues lorsque je joins la table des assets à la table des ports.

EDIT: c'est la nouvelle requête avec laquelle je travaille car les anciennes sont inutiles à ce stade. Mon problème avec cette nouvelle requête est qu'il semble tirer deux fois les éléments qui sont liés à la table port_connections. Donc, je vais obtenir l'enregistrement port_connections correct et puis je reçois un enregistrement en double avec seulement le port unique sans port_connection. Je dois me débarrasser de cet enregistrement plus tard mais garder les autres enregistrements de port qui n'ont pas d'enregistrement port_connection.

SELECT 
port_connections.connection_id, 

asset_a.name AS asset_a_name, 
port_a.port AS port_a_name, 
port_a.asset_id as asset_a, 

asset_b.name AS asset_b_name, 
port_b.port AS port_b_name, 
port_b.asset_id as asset_b, 

port_connections.description 

FROM 
port_connections 

right JOIN ports AS port_a 
ON port_connections.port_id_a = port_a.port_id 

right JOIN ports AS port_b 
ON port_connections.port_id_b = port_b.port_id 

left JOIN assets as asset_a 
ON asset_a.asset_id = port_a.asset_id 

left JOIN assets as asset_b 
ON asset_b.asset_id = port_b.asset_id 



WHERE 
(port_a.asset_id = 2 OR port_b.asset_id = 2) 
ORDER BY port_a_name, port_b_name 

Tableaux: actifs:

ASSET_ID 
SYS_ID 
LOCATION_ID 
NAME 
DESCRIPTION 
"TYPE" 
AQUIRED 
DISPOSED 
MFG_NAME 
TAG_NO 

port_connections

"CONNECTION_ID" 
PORT_ID_A 
PORT_ID_B 
DESCRIPTION 

ports

PORT_ID 
ASSET_ID 
PORT 
TITLE 
DESCRIPTION 
"TYPE" 
SPEED 

EDIT: Le correctif a été de déplacer le connection_id dans la table des ports et e est la requête fait alors ce que je voulais.

SELECT 
port_connections.connection_id, 

asset_a.name AS asset_a_name, 
port_a.port AS port_a_name, 
port_a.asset_id as asset_a, 

asset_b.name AS asset_b_name, 
port_b.port AS port_b_name, 
port_b.asset_id as asset_b, 

port_connections.description 

FROM 
port_connections 



right JOIN ports AS port_b 
ON port_connections.connection_id = port_b.connection_id 

right JOIN ports AS port_a 
ON port_connections.connection_id = port_a.connection_id 

left JOIN assets as asset_a 
ON asset_a.asset_id = port_a.asset_id 

left JOIN assets as asset_b 
ON asset_b.asset_id = port_b.asset_id 

WHERE 

port_a.asset_id = 2 
AND 
(port_b.asset_id != 2 or port_b.asset_id is null) 

ORDER BY port_a_name 
+0

Serait-il possible de modifier votre question pour inclure le schéma de ces trois tables? J'essaie de donner un sens aux jointures et c'est difficile sans une disposition de table pour le mettre ensemble. – SqlRyan

Répondre

1

J'ai modifié votre requête pour la compiler et l'inclure ci-dessous. L'erreur que vous voyez sur le nom de la table inattendue est sur la ligne INNER JOIN - vous avez donné le nom de la table de gauche, et vous n'avez pas besoin, puisque SQL utilise les critères de jointure (la clause ON) pour déterminer ce que la gauche la table est.

Est-ce que cela retourne toutes les lignes que vous attendez, ou vous attendez-vous à voir des résultats que vous n'êtes pas?

SELECT 
port_connections.connection_id, 

asset_a.name AS asset_a_name, 
port_a.port AS port_a_name, 
port_a.asset_id as asset_a, 

asset_b.name AS asset_b_name, 
port_b.port AS port_b_name, 
port_b.asset_id as asset_b, 

port_connections.description 

FROM 
port_connections 
RIGHT JOIN ports AS port_a 
ON port_connections.port_id_a = port_a.port_id 

RIGHT JOIN ports AS port_b 
ON port_connections.port_id_b = port_b.port_id 

INNER JOIN assets as asset_a 
ON asset_a.asset_id = port_a.asset_id 

INNER JOIN assets as asset_b 
ON asset_b.asset_id = port_b.asset_id 

WHERE 
(asset_a.asset_id = 2 OR asset_b.asset_id = 2) 

ORDER BY port_a_name, port_b_name 

EDIT: Je pense que je vois ce qui se passe ici. Étant donné que vous avez DROIT JOIN-ing depuis Connections vers "port a", il retournera ces lignes même si INNER JOIN plus tard (port a à asset a) n'a pas de correspondance, à cause de la manière dont le RIGHT JOIN se comporte. Pour exclure les lignes qui ne sont pas branchés, je pense que vous aurez juste besoin de modifier la clause WHERE:

WHERE 
(asset_a.asset_id = 2 OR asset_b.asset_id = 2) 
    AND asset_a.asset_id IS NOT NULL 

Ce filtrera les lignes pour lesquelles asset_a est NULL, à savoir là où il n'y a pas de match parce que rien est branché.

+0

Cela a fonctionné (moins les deux virgules). J'ai changé les jointures internes aux jointures gauches et maintenant il semble proche cependant il obtient des disques supplémentaires. Par exemple, j'ai un ordinateur/actif avec un port et un port_connection à un port sur un routeur. Cette nouvelle requête me donnera l'ordinateur comme asset_a et le routeur comme asset_b, c'est correct. L'enregistrement suivant a asset_a null et l'ordinateur sous asset_b. Il semble que ce soit en train de lier port_id_a et port_id_b dans la jointure afin qu'il apparaisse deux fois même si l'enregistrement du port de l'ordinateur est uniquement lié une fois sur port_connections.port_id_a. – Blake

+0

Vous obtiendriez des enregistrements supplémentaires si vous ne vous joignez pas à la clé entière dans l'une de vos jointures gauche/droite - si, par exemple, votre clé est composée pour portname et computername, mais que vous ne rejoignez que sur computername, avoir deux enregistrements pour port, et il ne sait pas à laquelle se joindre à, de sorte qu'il retournera les deux. Est-ce ce qui se passe? Pour le dire, vous devrez peut-être développer votre liste SELECT pour inclure des champs supplémentaires de votre table d'ordinateur pour voir quels champs sont à l'origine des doublons. – SqlRyan

+0

Mes clés sont port_id sur la table des ports et asset_id dans la table des assets. Pour un seul ordinateur avec un port, il renvoie asset_a/port_a en tant qu'ordinateur, asset_b/port_b en tant que routeur sur lequel il est branché. L'enregistrement suivant est un doublon des informations de l'ordinateur sous asset_b/port_b et null asset_a/port_a. Où il apparaît (sous a ou b) a à voir avec l'ordre de mes jointures mais peu importe ce que j'essaie je ne peux pas me débarrasser de ces doublons. Si je pouvais en quelque sorte définir un distinct, chaque port n'est listé qu'une seule fois entre les tables d'alias port_a et port_b. – Blake

Questions connexes