2010-03-19 19 views
12

Trong SQL Server 2008, tôi có câu hỏi sau đây:Tại sao phần bên trái của tôi không trả về giá trị rỗng?

select  
    c.title as categorytitle, 
    s.title as subcategorytitle, 
    i.title as itemtitle 
from categories c 
join subcategories s on c.categoryid = s.categoryid 
left join itemcategories ic on s.subcategoryid = ic.subcategoryid 
left join items i on ic.itemid = i.itemid and i.siteid = 132 
where (ic.isactive = 1 or ic.isactive is null) 
order by c.title, s.title 

tôi đang cố gắng để có được các mục trong danh mục con của họ, nhưng tôi vẫn muốn quay trở lại mức kỷ lục nếu không có mục trong hạng mục hoặc tiểu thể loại. Các danh mục phụ không có mục nào sẽ không bao giờ được trả lại. Tôi đang làm gì sai?

Cảm ơn bạn

EDIT

truy vấn thay đổi với một trái thứ hai tham gia và mệnh đề where, nhưng nó vẫn không trở về null. :/

EDIT 2

Moved SiteID đến mục chưa tham gia. Khi tôi làm điều này tôi nhận được nhiều hồ sơ hơn dự kiến. Một số mục có một siteid rỗng và tôi chỉ muốn bao gồm chúng khi chúng có một id cụ thể.

EDIT 3

Bảng cấu trúc:

Categories Table 
------- 
CategoryID 
Title 

SubCategories Table 
------- 
SubCategoryID 
CategoryID 
Title 

ItemCategories Table 
------- 
ItemCategoryID 
ItemID 
SubCategoryID 
IsActive 

Items Table 
-------- 
ItemID 
Title 
SiteID 
+0

nếu bạn thực sự muốn truy vấn của bạn quá hoạt động, hãy đăng cấu trúc bảng và ai đó ở đây có thể viết nó, nếu không chỉ có rất nhiều đoán đang diễn ra. –

+0

@ Griz, bạn có nhìn vào câu trả lời của tôi không? – Unreason

Trả lời

26

thay đổi join items i ... để LEFT join items i ... và truy vấn của bạn nên làm việc như bạn mong đợi.

EDIT
Bạn không thể lọc LEFT JOIN bảng trong mệnh đề where trừ khi bạn chiếm null, vì bên trái tham gia cho phép các cột phải có một giá trị hoặc được null khi không có hàng phù hợp:

and i.siteid = 132 sẽ vứt bỏ bất kỳ hàng nào của bạn có NULL i.siteid, nơi không tồn tại.Di chuyển này đến ON:

left join items i on ic.itemid = i.itemid and i.siteid = 132

hoặc làm WHERE xử lý NULLs:

WHERE ... AND (i.siteid = 132 OR i.siteid IS NULL)

EDIT dựa trên chỉnh sửa OP của 3

SET NOCOUNT ON 
DECLARE @Categories table (CategoryID int,Title varchar(30)) 
INSERT @Categories VALUES (1,'Cat AAA') 
INSERT @Categories VALUES (2,'Cat BBB') 
INSERT @Categories VALUES (3,'Cat CCC') 

DECLARE @SubCategories table (SubCategoryID int,CategoryID int,Title varchar(30)) 
INSERT @SubCategories VALUES (1,1,'SubCat AAA A') 
INSERT @SubCategories VALUES (2,1,'SubCat AAA B') 
INSERT @SubCategories VALUES (3,1,'SubCat AAA C') 
INSERT @SubCategories VALUES (4,2,'SubCat BBB A') 

DECLARE @ItemCategories table (ItemCategoryID int, ItemID int, SubCategoryID int, IsActive char(1)) 
INSERT @ItemCategories VALUES (1,1,2,'Y') 
INSERT @ItemCategories VALUES (2,2,2,'Y') 
INSERT @ItemCategories VALUES (3,3,2,'Y') 
INSERT @ItemCategories VALUES (4,4,2,'Y') 
INSERT @ItemCategories VALUES (5,7,2,'Y') 

DECLARE @Items table (ItemID int, Title varchar(30), SiteID int) 
INSERT @Items VALUES (1,'Item A',111) 
INSERT @Items VALUES (2,'Item B',111) 
INSERT @Items VALUES (3,'Item C',132) 
INSERT @Items VALUES (4,'Item D',111) 
INSERT @Items VALUES (5,'Item E',111) 
INSERT @Items VALUES (6,'Item F',132) 
INSERT @Items VALUES (7,'Item G',132) 
SET NOCOUNT OFF 

Tôi không 100% chắc chắn OP là gì sau, điều này sẽ trả về tất cả thông tin có thể được tham gia khi siteid=132 như được đưa ra trong câu hỏi

SELECT 
    c.title as categorytitle 
     ,s.title as subcategorytitle 
     ,i.title as itemtitle 
     --,i.itemID, ic.SubCategoryID, s.CategoryID 
    FROM @Items       i 
     LEFT OUTER JOIN @ItemCategories ic ON i.ItemID=ic.ItemID 
     LEFT OUTER JOIN @SubCategories s ON ic.SubCategoryID=s.SubCategoryID 
     LEFT OUTER JOIN @Categories  c ON s.CategoryID=c.CategoryID 
    WHERE i.siteid = 132 

OUTPUT:

categorytitle     subcategorytitle    itemtitle 
------------------------------ ------------------------------ ------------------------------ 
Cat AAA      SubCat AAA B     Item C 
NULL       NULL       Item F 
Cat AAA      SubCat AAA B     Item G 

(3 row(s) affected) 

này sẽ liệt kê tất cả các loại, thậm chí nếu không có trận đấu với siteid=132

;WITH AllItems AS 
(
SELECT 
    s.CategoryID, ic.SubCategoryID, ItemCategoryID, i.ItemID 
     ,c.title AS categorytitle, s.title as subcategorytitle, i.title as itemtitle 
    FROM @Items       i 
     LEFT OUTER JOIN @ItemCategories ic ON i.ItemID=ic.ItemID 
     LEFT OUTER JOIN @SubCategories s ON ic.SubCategoryID=s.SubCategoryID 
     LEFT OUTER JOIN @Categories  c ON s.CategoryID=c.CategoryID 
    WHERE i.siteid = 132 
) 
SELECT 
    categorytitle, subcategorytitle,itemtitle 
    FROM AllItems 
UNION 
SELECT 
    c.Title, s.Title, null 
    FROM @Categories      c 
     LEFT OUTER JOIN @SubCategories s ON c.CategoryID=s.CategoryID 
     LEFT OUTER JOIN @ItemCategories ic ON s.SubCategoryID=ic.SubCategoryID 
     LEFT OUTER JOIN AllItems   i ON c.CategoryID=i.CategoryID AND s.SubCategoryID=i.SubCategoryID 
    WHERE i.ItemID IS NULL 
ORDER BY categorytitle,subcategorytitle 

OUTPUT:

categorytitle     subcategorytitle    itemtitle 
------------------------------ ------------------------------ ------------------------------ 
NULL       NULL       Item F 
Cat AAA      SubCat AAA A     NULL 
Cat AAA      SubCat AAA B     Item C 
Cat AAA      SubCat AAA B     Item G 
Cat AAA      SubCat AAA C     NULL 
Cat BBB      SubCat BBB A     NULL 
Cat CCC      NULL       NULL 

(7 row(s) affected) 
+1

hãy thử với WHERE ... AND (i.siteid = 132 HOẶC i.itemid IS NULL): D – Unreason

+0

bạn không cần truy vấn đệ quy để nhận được truy vấn cuối cùng, chúng thường đắt tiền – Unreason

+2

@goran, không có truy vấn đệ quy bất cứ nơi nào trong câu trả lời của tôi. cách duy nhất để thực hiện truy vấn đệ quy trong TSQL là với CTE đệ qui và không có câu trả lời nào trong câu trả lời của tôi, thậm chí không phải là CTE thông thường. –

-3

. Hãy thử thay đổi tham gia của các mục để tham gia trái là tốt.

1

Có lẽ sự tham gia này cũng phải là một kết nối bên trái?

join items i on ic.itemid = i.itemid and i.siteid = 132 

EDIT:

Bây giờ bạn chọn id trang web duy nhất tồn tại trong mệnh đề where:

i.siteid = 132 

Nó sẽ cho phép các giá trị null, hãy thử một cái gì đó như thế này:

(i.siteid = 132 or i.siteid is null) 

hoặc bạn có thể di chuyển i.siteid = 132 trở lại điều kiện tham gia

+0

Cảm ơn .. Điều này đã giúp. –

5

Tiêu chí "WHERE" của bạn trên i.siteid có nghĩa là phải có hàng "mục" ở đầu ra. bạn cần phải viết (i.siteid là null hoặc i.siteid = 132) hoặc đặt "i.siteid = 132" vào mệnh đề "ON" - một thứ sẽ hoạt động cho itemcategories cũng tham gia:

select  
    c.title as categorytitle, 
    s.title as subcategorytitle, 
    i.title as itemtitle 
from categories c 
join subcategories s on c.categoryid = s.categoryid 
left join itemcategories ic on s.subcategoryid = ic.subcategoryid and ic.isactive = 1 
left join items i on ic.itemid = i.itemid and i.siteid = 132 
order by c.title, s.title 
+0

Khi tôi thực hiện sửa đổi này, tôi nhận được hơn 10.000 hồ sơ, nhưng không được quá ~ 30 trả lại. – jimj

+0

@Griz bạn nhận được hàng nào mà bạn không mong đợi? họ có tiểu thể loại sai, siteid không? hoặc bạn nhận được nhiều bản sao? – araqnid

+0

Nó dường như trả về các mục với bất kỳ siteid nào. – jimj

0
where (ic.isactive = 1 or ic.isactive is null) and i.siteid = 132 

Có i.siteID = 132 trong mệnh đề where của bạn về cơ bản vô hiệu hóa việc tham gia trái vào các mục.

0

Lần thử thứ hai, tôi nghĩ rằng tôi đã gặp sự cố của bạn ngay bây giờ. Nếu tôi hiểu chính xác thì điều xảy ra là bạn kết thúc với hai loại NULL trong SiteID trong trường hợp của bạn (trường hợp khi bạn thấy 10.000 kết quả, nhưng điều đó vẫn đang đi đúng hướng).

Có NULLs đến từ bên trái tham gia và những người đến từ thực tế mục bảng trang web. Bạn muốn có những người đến từ bên trái tham gia, nhưng không muốn những người từ dữ liệu.

Đây là lỗi rất phổ biến với các kết nối bên ngoài khi kiểm tra sự tồn tại của các hàng phù hợp.Hãy nhớ rằng nếu bạn muốn các hàng chưa từng có nên luôn luôn kiểm tra NULL chỉ trên các cột được định nghĩa là NOT NULL (khóa chính từ bảng bên ngoài là một ứng cử viên tự nhiên ở đây). Nếu không, bạn không thể phân biệt giữa các hàng là NULL do tham gia LEFT và các hàng sẽ là NULL ngay cả khi đó là INNER tham gia

Ít nhất hai cách để thực hiện việc này: a) để lại tham gia vào truy vấn phụ lọc ra các hàng với SiteID là null trước bên trái tham gia đá trong
b) viết lại tiêu chí (giả sử ItemID là cần thiết trong Items) để nói

select  
    c.title as categorytitle, 
    s.title as subcategorytitle, 
    i.title as itemtitle 
from categories c 
join subcategories s on c.categoryid = s.categoryid 
left join itemcategories ic on s.subcategoryid = ic.subcategoryid 
left join items i on ic.itemid = i.itemid 
where (ic.isactive = 1 or ic.isactive is null) AND (i.siteid = 132 or i.itemid is null) 
order by c.title, s.title 

(tôi giả định rằng các truy vấn đến tham gia vào bảng mục đã cho bạn những gì bạn mong đợi).

Nếu itemid là bắt buộc trong mục thì điều kiện trên cho biết - hàng có siteid 132 hoặc hàng thực sự đến từ bên trái chưa được khớp (lưu ý rằng điều kiện ở trên i.itemid là null và không phải i.siteid là rỗng) .