web-dev-qa-db-ja.com

SQL Server:WHERE句を使用した複数のテーブル結合

私はSQL Serverを使用していますが、必要なSELECTクエリから結果を取得するのに苦労しています。さまざまな順序でサブクエリを使用して参加しようとしましたが、希望どおりに機能するものはありません。人々のコンピューターにインストールされる可能性のある、さまざまなバージョンレベルのソフトウェアアプリケーションのこの不自然な例を見てみましょう。

JOINWHEREを実行する必要がありますが、何らかの理由で必要な結果が得られません。

データを間違って見ているのかもしれませんが、なぜこれが機能しないのかよくわかりません。

アプリケーションテーブル

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 junctionテーブル

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

コンピューターテーブル

ID  ComputerName
1   Name1
2   Name2

特定のコンピューターを選択して実行できるクエリが必要で、ソフトウェアのバージョンとアプリケーションの種類を表示しますが、それが持っていないアプリケーションも表示したいです(バージョンは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

RIGHT JOINは、コンピューターに関連付けられていない場合でも、すべての結果をアプリケーションテーブルに含めます。何が欠けている/間違っているのですか?

16
Stormchao

LEFT JOINまたはRIGHT JOINを使用する場合、フィルターをWHEREに配置するかJOINに配置するかによって違いが生じます。

少し前に書いた同様の質問に対するこの回答をご覧ください。
2つの異なる結果セットを取得する場合のこれら2つのクエリの違いは何ですか?

要するに:

  • それをWHERE句に入れると(あなたがしたように、そのコンピューターに関連付けられていない結果は完全に除外されます)
  • 代わりにJOINに入れると、そのコンピューターに関連付けられていない結果がクエリ結果に表示され、NULL値のみが表示されます
    ->これはあなたが望むものです
13

期待する3番目の行(PowerPointのある行)は、Computer.ID = 1条件(Computer.ID = 1 or Computer.ID is nullそれは何が起こるかを見るために)。

ただし、特定のコンピューターのリストが必要なので、その条件を削除しても意味がありません。

私が見る唯一の解決策は、元のクエリと、そのコンピュータでnotであるアプリケーションのリストを取得する新しいクエリとの間で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
8

これを試して

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
2
Oleg Dok

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)のすべてのレコードが含まれます。 (B)。これは、ON句がBの0(ゼロ)レコードと一致する場合、結合は結果に行を返しますが、Bの各列にNULLを含むことを意味します。つまり、左外部結合は左からすべての値を返しますテーブル、および右側のテーブルからの一致した値(または一致する結合述語がない場合はNULL)。右側のテーブルが1つの行を返し、左側のテーブルがそれに一致する複数の行を返す場合、右側のテーブルの値は左側のテーブルの個別の行ごとに繰り返されます。 Oracle 9i以降では、LEFT OUTER JOINステートメントと(+)を使用できます。

1
aF.
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;
1
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 
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 
0
Gyan Singh

c.ComputerName、S.Version、A.NameをコンピューターCの内部結合から選択Software_Computer SC = SC.ComputerId内部結合SC.SoftwareIDのSoftware S = S.Id内部結合S.ApplicationId = A.IdのアプリケーションA

0
aman