2013-05-09 29 views
5

Tôi đang gặp một số vấn đề với truy vấn SQL cũ đơn giản (nhược điểm của việc sử dụng ORM hầu hết thời gian :)).Tìm tất cả các hàng có 2 điều kiện bằng cách sử dụng SQL (bảng riêng biệt)

Tôi đang có 2 bảng, PRODUCTSRULES. Trong bảng RULES Tôi đã xác định các quy tắc cho sản phẩm. Những gì tôi muốn là viết một truy vấn để có được tất cả các sản phẩm có quy tắc được xác định.

quy tắc được xác định bởi 2 cách:

  1. Bạn có thể chỉ định RULE cho chỉ có một sản phẩm (ProductID có giá trị, SectorID là NULL)
  2. Bạn có thể chỉ định RULE để biết thêm rằng một trong những sản phẩm sử dụng SectorID (ProductID là NULL)

Kết quả cần có tất cả các sản phẩm có quy tắc (product.ID - rule.ProductID) nhưng cũng tất cả các sản phẩm có ar e được xác định trong các lĩnh vực có trong bảng quy tắc (product.SectorID - rule.SectorID).

Ngoài ra, kết quả không thể có sản phẩm trùng lặp (sản phẩm được xác định bởi productId trong RULES hoặc bằng SectorID)

Ví dụ:

HÀNG

ID SectorID 
1 1 
2 1 
3 1 
4 2 
5 3 
6 3 

QUY

ID ProductID SectorID 
1 1   NULL 
4 NULL  1 
5 6   NULL 

Kết quả mong đợi

PRODUCTS with IDs : 1, 2, 3, 6 

Trả lời

4

Cách đơn giản nhất tôi có thể nghĩ đến, nhưng không nhất thiết phải nhanh nhất.

SELECT * FROM products AS p WHERE 
     EXISTS (SELECT * FROM rules AS r WHERE p.ID = r.ProductID OR p.SectorID = r.SectorID) 
+1

Điều này * sẽ * có thể là nhanh nhất (được đưa ra chỉ mục có liên quan). Tách OR thành hai chân EXISTS riêng biệt có thể cải thiện mọi thứ: 'WHERE EXISTS (... trong đó p.ID = r.ProductID) OR EXISTS (... WHERE p.SectorID = r.SectorID)' – wildplasser

+0

@wildplasser Theo như Tôi có thể nói, [truy vấn được viết lại như là một tham gia anyway] (http://sqlfiddle.com/#!6/7c91c/2) với cùng một kế hoạch như tham gia dưới đây. –

2

Thực hiện cả hai truy vấn và kết hợp các kết quả:

SELECT ProductID FROM Rules 
WHERE ProductID IS NOT NULL 
UNION 
SELECT p.ID FROM Product p 
INNER JOIN Rules r ON p.SectorID = r.SectorID 

Các UNION sẽ lọc ra ID trùng lặp. Giả sử ví dụ của bạn được đơn giản hóa, bạn có thể sử dụng điều này làm truy vấn phụ để có danh sách tất cả các sản phẩm có quy tắc và sử dụng để kết hợp với các bảng khác để trả về dữ liệu bắt buộc.

Một cách tiếp cận khác:

SELECT DISTINCT p.ID FROM Product p 
INNER JOIN Rules r 
ON p.ID = r.ProductID OR p.SectorID = r.SectorID 

Những thể hoặc không thể tạo ra kế hoạch thực hiện khác nhau. Bạn nên kiểm tra và chọn nhanh hơn.

+1

trong truy vấn đầu tiên của bạn tham gia vào bảng sản phẩm là không cần thiết. Chỉ cần trả về 'r.productID'. Tiết kiệm một tham gia luôn luôn là một điều tốt ;-) –

+1

và thay thế sẽ nhận được bản sao – cmd

+0

@cmd, Declan_K Thật vậy; cảm ơn. –

1
select distinct 
     ProductID 
from rules 
where ProductID is not null 
union 
select distinct 
     p.id 
from PRODUCTS p 
inner join 
     RULES r 
on  r.sectorid = p.sectorid 

đây là SQL Fiddle

+1

Việc sử dụng riêng biệt là không cần thiết. Phần thứ hai của liên minh sẽ không trả lại bất kỳ bản sao nào. Lần đầu tiên có thể, nhưng công đoàn sẽ lọc chúng ra, ngay cả khi các giá trị trùng lặp không xuất hiện trong nửa thứ hai. –

+0

Điểm tốt. Ngoài ra, tôi nghĩ câu trả lời của Joachim tốt hơn tôi. –

3

Để có được các hàng sản phẩm hoàn chỉnh cho các sản phẩm phù hợp, đó là một đơn giản JOIN. Yêu cầu DISTINCT vì sản phẩm có thể khớp với cả quy tắc sản phẩm và quy tắc ngành và bạn chỉ muốn nó được liệt kê một lần.

SELECT DISTINCT p.* 
FROM products p 
JOIN rules r 
    ON p.ID  = r.ProductID 
    OR p.SectorID = r.SectorID 

An SQLfiddle to test with.

0

Tôi tin rằng một cái gì đó như thế này nên làm việc:

SELECT DISTINCT p.id 
FROM Products p 
LEFT JOIN Rules r1 ON p.id = r1.productID 
LEFT JOIN Rules r2 ON p.SectorID = r2.SectorID 
WHERE r1.id IS NOT NULL OR r2.SectorID IS NOT NULL 
ORDER BY p.id; 

SQL Fiddle

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