J'utilise SQL Server et j'ai du mal à obtenir les résultats d'une requête SELECT
que je souhaite. J'ai essayé de joindre différents ordres et d'utiliser des sous-requêtes, mais rien ne fonctionne comme je le souhaite. Prenons cet exemple artificiel d’applications logicielles, avec différents niveaux de version, pouvant être installées sur des ordinateurs.
Je dois effectuer un JOIN
avec un WHERE
, mais pour une raison quelconque, je ne parviens pas à obtenir les résultats souhaités.
Peut-être que je regarde mal mes données, je ne sais pas trop pourquoi je ne peux pas faire en sorte que cela fonctionne.
Application table
ID Name
1 Word
2 Excel
3 PowerPoint
Software Table (contient les informations de version pour différentes applications)
ID ApplicationID Version
1 1 2003
2 1 2007
3 2 2003
4 2 2007
5 3 2003
6 3 2007
Software_Computer table de jonction
ID SoftwareID ComputerID
1 1 1
2 4 1
3 2 2
4 5 2
Ordinateur table
ID ComputerName
1 Name1
2 Name2
Je veux une requête que je pourrais exécuter où je sélectionne un ordinateur spécifique pour afficher quelle version de logiciel et d'application est, mais je veux aussi qu'il affiche quelle application il n'a pas (la version serait un NULL
puisqu'elle n'a pas ce logiciel dessus)
SELECT Computer.ComputerName, Application.Name, Software.Version
FROM Computer
JOIN Software_Computer
ON Computer.ID = Software_Computer.ComputerID
JOIN Software
ON Software_Computer.SoftwareID = Software.ID
RIGHT JOIN Application
ON Application.ID = Software.ApplicationID
WHERE Computer.ID = 1
Je veux le jeu de résultats suivant
ComputerName Name Version
Name1 Word 2003
Name1 Excel 2007
Name1 PowerPoint NULL
Mais je viens d'avoir
Results
ComputerName Name Version
Name1 Word 2003
Name1 Excel 2007
Je pensais que le RIGHT JOIN
inclurait tous les résultats dans la table d'application, même s'ils n'étaient pas associés à l'ordinateur. Qu'est-ce qui me manque/je fais mal?
Lorsque vous utilisez LEFT JOIN
ou RIGHT JOIN
, le fait que le filtre soit placé dans WHERE
ou dans JOIN
fait une différence.
Voir cette réponse à une question similaire que j'ai écrite il y a quelque temps:
Quelle est la différence entre ces deux requêtes en tant qu'obtention de deux résultats différents?
En bref:
WHERE
(comme vous l'avez fait, les résultats qui ne sont pas associés à cet ordinateur sont complètement filtrésJOIN
, les résultats qui ne sont pas associés à cet ordinateur apparaissent dans le résultat de la requête, uniquement avec les valeurs NULL
.La troisième ligne que vous attendez (celle avec PowerPoint) est filtrée par la condition Computer.ID = 1
(essayez d'exécuter la requête avec le Computer.ID = 1 or Computer.ID is null
pour voir ce qui se passe).
Cependant, supprimer cette condition n’aurait aucun sens, car, après tout, nous voulons la liste pour un ordinateur donné.
La seule solution que je vois consiste à effectuer une union entre votre requête d'origine et une nouvelle requête qui récupère la liste des applications qui sont pas trouvées sur cet ordinateur.
La requête pourrait ressembler à ceci:
DECLARE @ComputerId int
SET @ComputerId = 1
-- your original query
SELECT Computer.ComputerName, Application.Name, Software.Version
FROM Computer
JOIN dbo.Software_Computer
ON Computer.ID = Software_Computer.ComputerID
JOIN dbo.Software
ON Software_Computer.SoftwareID = Software.ID
RIGHT JOIN dbo.Application
ON Application.ID = Software.ApplicationID
WHERE Computer.ID = @ComputerId
UNION
-- query that retrieves the applications not installed on the given computer
SELECT Computer.ComputerName, Application.Name, NULL as Version
FROM Computer, Application
WHERE Application.ID not in
(
SELECT s.ApplicationId
FROM Software_Computer sc
LEFT JOIN Software s on s.ID = sc.SoftwareId
WHERE sc.ComputerId = @ComputerId
)
AND Computer.id = @ComputerId
essaye ça
DECLARE @Application TABLE(Id INT PRIMARY KEY, NAME VARCHAR(20))
INSERT @Application ( Id, NAME )
VALUES ( 1,'Word' ), ( 2,'Excel' ), ( 3,'PowerPoint' )
DECLARE @software TABLE(Id INT PRIMARY KEY, ApplicationId INT, Version INT)
INSERT @software ( Id, ApplicationId, Version )
VALUES ( 1,1, 2003 ), ( 2,1,2007 ), ( 3,2, 2003 ), ( 4,2,2007 ),( 5,3, 2003 ), ( 6,3,2007 )
DECLARE @Computer TABLE(Id INT PRIMARY KEY, NAME VARCHAR(20))
INSERT @Computer ( Id, NAME )
VALUES ( 1,'Name1' ), ( 2,'Name2' )
DECLARE @Software_Computer TABLE(Id INT PRIMARY KEY, SoftwareId int, ComputerId int)
INSERT @Software_Computer ( Id, SoftwareId, ComputerId )
VALUES ( 1,1, 1 ), ( 2,4,1 ), ( 3,2, 2 ), ( 4,5,2 )
SELECT Computer.Name ComputerName, Application.Name ApplicationName, MAX(Software2.Version) Version
FROM @Application Application
JOIN @Software Software
ON Application.ID = Software.ApplicationID
CROSS JOIN @Computer Computer
LEFT JOIN @Software_Computer Software_Computer
ON Software_Computer.ComputerId = Computer.Id AND Software_Computer.SoftwareId = Software.Id
LEFT JOIN @Software Software2
ON Software2.ID = Software_Computer.SoftwareID
WHERE Computer.ID = 1
GROUP BY Computer.Name, Application.Name
Vous devez faire un LEFT JOIN
.
SELECT Computer.ComputerName, Application.Name, Software.Version
FROM Computer
JOIN dbo.Software_Computer
ON Computer.ID = Software_Computer.ComputerID
LEFT JOIN dbo.Software
ON Software_Computer.SoftwareID = Software.ID
RIGHT JOIN dbo.Application
ON Application.ID = Software.ApplicationID
WHERE Computer.ID = 1
Voici l'explication:
Résultat d'une jointure externe gauche (ou simplement gauche) pour la table A et B contient toujours tous les enregistrements de la table "gauche" (A), même si le condition de jointure ne trouve aucun enregistrement correspondant dans la "bonne" table (B). Cela signifie que si la clause ON correspond à 0 (zéro) enregistrement dans B, la jointure renverra toujours une ligne dans le résultat, mais avec NULL dans chaque column from B. Cela signifie qu'une jointure externe gauche renvoie tous les valeurs de la table de gauche, plus les valeurs correspondantes de la table de droite (ou NULL en cas d'absence de prédicat de jointure correspondant). Si la bonne table renvoie une ligne et la table de gauche renvoie plusieurs lignes correspondantes pour cela, les valeurs dans le tableau de droite seront répétées pour chaque ligne distincte sur la table de gauche. À partir d'Oracle 9i, les sorties LEFT OUTER L'instruction JOIN peut être utilisée aussi bien que (+).
SELECT p.Name, v.Name
FROM Production.Product p
JOIN Purchasing.ProductVendor pv
ON p.ProductID = pv.ProductID
JOIN Purchasing.Vendor v
ON pv.BusinessEntityID = v.BusinessEntityID
WHERE ProductSubcategoryID = 15
ORDER BY v.Name;
SELECT Computer.Computer_Name, Application1.Name, Max(Soft.[Version]) as Version1
FROM Application1
inner JOIN Software
ON Application1.ID = Software.Application_Id
cross join Computer
Left JOIN Software_Computer
ON Software_Computer.Computer_Id = Computer.ID and Software_Computer.Software_Id = Software.Id
Left JOIN Software as Soft
ON Soft.Id = Software_Computer.Software_Id
WHERE Computer.ID = 1
GROUP BY Computer.Computer_Name, Application1.Name
Essayez cela fonctionne bien ....
SELECT computer.NAME, application.NAME,software.Version FROM computer LEFT JOIN software_computer ON(computer.ID = software_computer.ComputerID)
LEFT JOIN software ON(software_computer.SoftwareID = Software.ID) LEFT JOIN application ON(application.ID = software.ApplicationID)
where computer.id = 1 group by application.NAME UNION SELECT computer.NAME, application.NAME,
NULL as Version FROM computer, application WHERE application.ID not in ( SELECT s.applicationId FROM software_computer sc LEFT JOIN software s
on s.ID = sc.SoftwareId WHERE sc.ComputerId = 1 )
AND computer.id = 1
sélectionnez C.ComputerName, S.Version, A.Name depuis l'ordinateur C interne rejoindre Software_Computer SC sur C.Id = SC.ComputerId Inner join Software S sur SC.SoftwareID = S.Id Jointure interne Application A sur S.ApplicationId = A.Id;