私は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 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
は、コンピューターに関連付けられていない場合でも、すべての結果をアプリケーションテーブルに含めます。何が欠けている/間違っているのですか?
LEFT JOIN
またはRIGHT JOIN
を使用する場合、フィルターをWHERE
に配置するかJOIN
に配置するかによって違いが生じます。
少し前に書いた同様の質問に対するこの回答をご覧ください。
2つの異なる結果セットを取得する場合のこれら2つのクエリの違いは何ですか?
要するに:
WHERE
句に入れると(あなたがしたように、そのコンピューターに関連付けられていない結果は完全に除外されます)JOIN
に入れると、そのコンピューターに関連付けられていない結果がクエリ結果に表示され、NULL
値のみが表示されます期待する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
これを試して
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
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ステートメントと(+)を使用できます。
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
これをうまく試してください....
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
c.ComputerName、S.Version、A.NameをコンピューターCの内部結合から選択Software_Computer SC = SC.ComputerId内部結合SC.SoftwareIDのSoftware S = S.Id内部結合S.ApplicationId = A.IdのアプリケーションA