SQL Server:具有WHERE子句的多个表连接

时间:2012-01-06 13:04:27

标签: sql-server join where

我正在使用SQL Server,我很难尝试从我想要的SELECT查询中获取结果。我尝试过加入不同的命令并使用子查询,但没有什么能按我想要的方式工作。以这个人为计算机上可能安装的具有不同版本级别的软件应用程序为例。

我需要使用JOIN执行WHERE,但出于某种原因,我无法获得我想要的结果。

也许我正在查看我的数据错误,我不太清楚为什么我不能让它工作。

申请

ID  Name
1   Word
2   Excel
3   Powerpoint

软件表(包含不同应用程序的版本信息)

ID  ApplicationID   Version
1   1             2003
2   1             2007
3   2             2003
4   2             2007
5   3             2003
6   3             2007

Software_Computer 联结表

ID  SoftwareID  ComputerID
1   1           1
2   4           1
3   2           2
4   5           2

计算机

ID  ComputerName
1   Name1
2   Name2

我想要一个查询,我可以在选择特定计算机的地方运行,以显示软件版本和应用程序的内容,但我也希望它显示它没有的应用程序(版本为{{1}因为它上面没有那个软件)

NULL

我想要以下结果集

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 

但我得到了

ComputerName   Name          Version
Name1          Word          2003
Name1          Excel         2007
Name1          Powerpoint    NULL

我认为Results ComputerName Name Version Name1 Word 2003 Name1 Excel 2007 将包含应用程序表中的所有结果,即使它们与计算机无关。我错过了什么/做错了什么?

8 个答案:

答案 0 :(得分:13)

使用LEFT JOINRIGHT JOIN时,无论是将过滤器放在WHERE还是放入JOIN,都会有所不同。

请参阅我之前写的类似问题的答案:
What is the difference in these two queries as getting two different result set?

简而言之:

  • 如果您将其放入WHERE子句中(与您一样,与该计算机无关的结果将被完全过滤掉
  • 如果您将其放入JOIN,则与该计算机无关的结果会显示在查询结果中,仅显示NULL个值 - >这就是你想要的

答案 1 :(得分:8)

您期望的第三行(使用Powerpoint的那一行)被Computer.ID = 1条件过滤掉(尝试使用Computer.ID = 1 or Computer.ID is null运行查询,看看会发生什么)。

但是,删除这个条件没有意义,因为毕竟我们想要一个给定计算机的列表。

我看到的唯一解决方案是在原始查询和新查询之间执行UNION,该查询检索在该计算机上找到的应用程序列表。

查询可能如下所示:

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

答案 2 :(得分:2)

试试这个

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

答案 3 :(得分:1)

您需要执行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 

以下是解释:

  

表A和表的左外连接(或简称左连接)的结果   B总是包含“左”表(A)的所有记录,即使是   join-condition在“右”表中找不到任何匹配的记录   (B)。这意味着如果ON子句匹配B中的0(零)记录,   连接仍会在结果中返回一行 - 但每个中都有NULL   来自B的列。这意味着左外连接返回所有   左表中的值加上右表中的匹配值   (如果没有匹配的连接谓词,则为NULL)。如果是正确的表   返回一行,左表返回多个匹配的行   对于它,右表中的值将重复   左表上的不同行。从Oracle 9i开始,LEFT OUTER   可以使用JOIN语句以及(+)。

答案 4 :(得分:1)

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;

答案 5 :(得分:0)

试试这个工作正常......

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 

答案 6 :(得分:0)

选择C.ComputerName,S.Version,A.Name    来自Computer C内部加入Software_Computer SC      在C.Id = SC.ComputerId    内连接软件S.      在SC.SoftwareID = S.Id上    内连接应用程序A.       在S.ApplicationId = A.Id;

答案 7 :(得分:0)

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