2012-01-06 23 views
16

Tôi đang sử dụng SQL Server và tôi đang gặp khó khăn khi cố gắng lấy kết quả từ truy vấn SELECT mà tôi muốn. Tôi đã thử tham gia vào các đơn đặt hàng khác nhau và sử dụng truy vấn phụ nhưng không có gì hoàn toàn hoạt động theo cách tôi muốn. Lấy ví dụ này về các ứng dụng phần mềm, với các mức phiên bản khác nhau, có thể được cài đặt trên máy tính của mọi người.Máy chủ SQL: Nhiều bảng kết hợp với mệnh đề WHERE

Tôi cần thực hiện JOIN với WHERE, nhưng vì một lý do nào đó tôi không thể nhận được kết quả mình muốn.

Có lẽ tôi đang xem dữ liệu của mình sai, tôi không hoàn toàn chắc chắn lý do tại sao tôi không thể làm việc này.

Application bảng

ID Name 
1 Word 
2 Excel 
3 Powerpoint 

Software Bảng (chứa thông tin phiên bản cho các ứng dụng khác nhau)

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

Software_Computer bảng ngã ba

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

Computer bảng

ID ComputerName 
1 Name1 
2 Name2 

Tôi muốn có một truy vấn mà tôi có thể chạy mà tôi chọn một máy tính cụ thể để hiển thị những gì phiên bản phần mềm và ứng dụng được có, nhưng tôi cũng muốn nó hiển thị những gì ứng dụng nó không có (phiên bản sẽ là một NULL vì nó không có mà phần mềm trên nó)

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 

tôi muốn các kết quả sau thiết

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

Nhưng tôi chỉ nhận được

Results 
ComputerName Name   Version 
Name1   Word   2003 
Name1   Excel   2007 

Tôi nghĩ RIGHT JOIN sẽ bao gồm tất cả các kết quả trong bảng ứng dụng, ngay cả khi họ không liên quan đến máy tính. Tôi đang thiếu gì/làm sai?

+0

Có thể là cos tôi cao, nhưng bạn không phải là ứng dụng của phần mềm máy tính? Và không chỉ có hai phần mềm thuộc về máy tính 1? Ngoài ra, không nên tham gia bên trái ghi đè quyền tham gia? Rằng tôi cần kiểm tra. Và PowerPoint có một phiên bản vậy tại sao bạn mong đợi null? Ngoài ra, với nhiều phiên bản cho các ứng dụng, trong bảng phần mềm máy tính, bạn cũng cần duy trì một phiên bản id, nếu không bạn sẽ có tất cả các kết quả sai lệch. – frostymarvelous

Trả lời

12

Khi sử dụng LEFT JOIN hoặc RIGHT JOIN, nó làm cho một sự khác biệt cho dù bạn đặt bộ lọc vào WHERE hoặc vào JOIN.

Xem câu trả lời này cho một câu hỏi tương tự như tôi đã viết một số thời gian trước đây:
What is the difference in these two queries as getting two different result set?

Nói tóm lại:

  • nếu bạn đặt nó vào mệnh đề WHERE (như bạn đã làm, những kết quả mà aren Không được liên kết với máy tính đó, hãy lọc hoàn toàn
  • nếu bạn đặt nó vào JOIN thay vào đó, kết quả không được liên kết với máy tính đó xuất hiện trong kết quả truy vấn, chỉ với NULL đánh giá cao
    -> đây là những gì bạn muốn
+0

Điều này có vẻ là những gì tôi đã mất tích. Tôi vừa thử nghiệm nó và có vẻ như đang tạo ra kết quả tôi muốn. Cảm ơn bạn. – Stormchao

+0

Kết quả mong đợi là có "name1" được liệt kê với "powerpoint". Việc thêm "computer.ID = 1" vào kết nối không cho kết quả mong đợi. Hàng có giá trị "powerpoint" sẽ có cột tên máy tính của nó là giá trị null. Giữa các giải pháp của w0lf và Oleg, oleg là tốt hơn trong hai. –

1

Bạn cần thực hiện 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 

Dưới đây là lời giải thích:

Kết quả của một trái bên ngoài tham gia (hoặc đơn giản là để lại tham gia) cho bảng A và B luôn chứa tất cả hồ sơ của bảng "left" (A), ngay cả khi điều kiện tham gia không tìm thấy bất kỳ bản ghi phù hợp nào trong bảng "bên phải" (B). Điều này có nghĩa rằng nếu mệnh đề ON khớp với 0 (0) bản ghi trong B, tham gia sẽ vẫn trả về một hàng trong kết quả - nhưng với NULL trong mỗi cột từ B. Điều này có nghĩa là một bên ngoài bên ngoài trả về tất cả các giá trị từ bảng bên trái, cộng với các giá trị được so khớp từ bảng bên phải (hoặc NULL trong trường hợp không có biến vị ngữ nối khớp).Nếu bảng bên phải trả về một hàng và bảng bên trái trả về nhiều hàng phù hợp cho nó, các giá trị trong bảng bên phải sẽ được lặp lại cho mỗi hàng riêng biệt trên bảng bên trái. Từ Oracle 9i trở đi, lệnh LEFT OUTER JOIN có thể được sử dụng cũng như (+).

+0

humm, tại sao downvote oO –

+0

Điều này không hoạt động. LEFT OUTER JOIN không thay đổi gì; tập kết quả trung gian vẫn có "name1" được kết hợp với "word" và "excel".Tham gia bên ngoài bên phải sẽ vẫn bao gồm "powerpoint" trong tập kết quả tiếp theo nhưng liên kết với giá trị NULL cho tên máy tính. Cuối cùng, điều kiện where loại bỏ bản ghi powerpoint khỏi tập kết quả vì giá trị null của nó cho tên máy tính <> "name1" –

7

Dòng thứ ba mà bạn mong đợi (một với Powerpoint) được lọc ra bởi tình trạng Computer.ID = 1 (thử chạy các truy vấn với Computer.ID = 1 or Computer.ID is null nó để xem những gì sẽ xảy ra) .

Tuy nhiên, bỏ điều kiện đó sẽ không có ý nghĩa, bởi vì sau khi tất cả, chúng tôi muốn danh sách cho một máy tính nhất định.

Giải pháp duy nhất tôi thấy đang thực hiện một UNION giữa truy vấn ban đầu của bạn và truy vấn mới truy xuất danh sách ứng dụng là không phải là được tìm thấy trên Máy tính đó.

Truy vấn có thể trông như thế này:

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 
+0

Cảm ơn bạn. Đây là hoàn hảo! Tôi đã cố gắng thực hiện quá nhiều với một SELECT duy nhất. Tôi sẽ upvote này nếu tôi có thể. – Stormchao

+0

Tôi biết đó là những gì bạn cần; nó rất rõ ràng từ câu hỏi. Tôi không chắc chắn tại sao tôi có một downvote về câu trả lời này mặc dù. Dù sao, tôi rất vui vì nó đã giúp. :-) – GolfWolf

+0

Nó không phải là biểu diễn như của Oleg. Ngoài ra, một số vấn đề nhỏ mà tôi có với nó là 1) UNION ALL vì các bộ đã được loại trừ lẫn nhau theo định nghĩa 2) rõ ràng hơn với CROSS JOIN –

2

thử này

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 
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; 
+0

Điều này không cung cấp câu trả lời cho câu hỏi. Để phê bình hoặc yêu cầu làm rõ từ tác giả, để lại nhận xét bên dưới bài đăng của họ - bạn luôn có thể nhận xét về bài đăng của riêng bạn và sau khi bạn có đủ [danh tiếng] (http://stackoverflow.com/help/whats-reputation), bạn sẽ có thể [nhận xét về bài đăng bất kỳ] (http://stackoverflow.com/help/privileges/comment). – Micha

0

Hãy thử điều này làm việc tốt ....

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

chọn C.ComputerName, S.Version, A.Name từ Máy tính C bên trong tham gia Software_Computer SC trên C.Id = SC.ComputerId Phần mềm nối bên trong S trên SC.SoftwareID = S.Id Ứng dụng nối bên trong A trên S.ApplicationId = A.Id;

Các vấn đề liên quan