2010-09-21 39 views
5

Tôi đang cố viết mã để kéo danh sách các mục sản phẩm từ cơ sở dữ liệu SQL Server hiển thị kết quả trên trang web.nhiều truy vấn chọn nhiều

Yêu cầu của dự án là danh sách các danh mục được hiển thị ở bên phải trang như danh sách hộp kiểm (tất cả các danh mục được chọn theo mặc định) và người dùng có thể bỏ chọn các danh mục và truy vấn lại cơ sở dữ liệu xem sản phẩm chỉ trong các danh mục mà họ muốn.

Heres nơi nó bắt đầu để có được một chút lông.

Mỗi sản phẩm có thể được assinged cho nhiều loại sử dụng một bảng các loại sản phẩm như sau ...

 
Product table 
[product_id](PK),[product_name],[product_price],[isEnabled],etc... 

Category table 
[CategoryID](PK),[CategoryName] 

ProductCagetory table 

[id](PK),[CategoryID](FK),[ProductID](FK) 

tôi cần phải chọn một danh sách các sản phẩm phù hợp với một bộ các hạng mục truyền cho thủ tục lưu trữ của tôi, nơi ID các sản phẩm có nhiều danh mục được chỉ định.

id categort của được truyền cho các proc như một dấu phẩy phân cách varchar ví dụ: (3,5,8,12)

Các phá vỡ SQL giá trị varchar này thành một resultset trong một bảng tạm thời để xử lý.

Làm cách nào tôi có thể gửi đi bằng văn bản truy vấn này?

+1

Bạn có muốn điều này độc quyền hoặc bao gồm? Ví dụ: nếu tôi chỉ kiểm tra danh mục 1 và 2, bạn có muốn xem tất cả các lần truy cập trong 1 HOẶC 2 hay chỉ những mục đó trong BOTH 1 AND 2? – JNK

+0

Vui lòng đăng những gì bạn có cho đến nay. –

Trả lời

-2

này nên được khá gần với những gì bạn đang tìm kiếm

SELECT product.* 
FROM product 
JOIN ProductCategory ON ProductCategory.ProductID = Product.product_id 
JOIN #my_temp ON #my_temp.category_id = ProductCategory.CategoryID 

EDIT

Như đã đề cập trong các ý kiến ​​này sẽ tạo ra các bản sao cho các sản phẩm xuất hiện trong nhiều loại. Để sửa lỗi này, hãy chỉ định DISTINCT trước danh sách cột. Tôi đã bao gồm tất cả các cột sản phẩm trong danh sách product.* vì tôi không biết bạn đang tìm cột nào nhưng có lẽ bạn nên thay đổi các cột cụ thể mà bạn muốn

+3

Nếu sản phẩm thuộc nhiều danh mục, truy vấn này sẽ tạo ra các bản sao. –

+0

Chúc mừng Steve, đã làm việc với điều trị –

+0

@Remus. Thật vậy nó.Đã chỉnh sửa để phản ánh rằng –

-1

Điều này sẽ thực hiện. Bạn không cần phải phân tách các id danh mục được phân tách bằng dấu phẩy.

select distinct p.* 
from product p, productcategory pc 
where p.product_id = pc.productid 
and pc.categoryid in (place your comma delimited category ids here) 

Điều này sẽ cung cấp cho sản phẩm có bất kỳ thông tin nào trong id danh mục, theo nhận xét của JNK là HOẶC không phải TẤT CẢ. Vui lòng chỉ định nếu bạn muốn có AND nghĩa là, sản phẩm chỉ cần được chọn nếu nó nằm trong TẤT CẢ các loại được chỉ định trong danh sách được phân tách bằng dấu phẩy.

+2

Vấn đề với việc đặt riêng biệt quá cao trên cây thực thi là nó sẽ phải sắp xếp có khả năng khá nhiều sản phẩm để có được những 'distict' và loại này là (rất) tốn kém. Tốt hơn là nên nhận các ID sản phẩm riêng biệt trước (ví dụ: chỉ phân loại ID) và sau đó tìm phần còn lại của thông tin sản phẩm. –

+0

Sử dụng DISTINCT làm băng tần cho nhu cầu bán tham gia: không quá tuyệt vời. – ErikE

-1

Nếu bạn cần gì khác hơn product_id từ các sản phẩm thì bạn có thể viết một cái gì đó như thế này (và thêm các trường bổ sung mà bạn cần):

SELECT distinct(p.product_id) 
FROM product_table p 
JOIN productcategory_table pc 
ON p.product_id=pc.product_id 
WHERE pc.category_id in (3,5,8,12); 

mặt khác nếu bạn cần thực sự chỉ là product_id bạn chỉ có thể chọn chúng từ productcategory_table:

SELECT distinct(product_id) 
FROM productcategory_table 
WHERE category_id in (3,5,8,12); 
+1

Giống như truy vấn của Steve, điều này tạo ra các bản sao cho các sản phẩm trong nhiều danh mục. –

+0

cố định bên phải của bạn, thx –

+0

Sử dụng DISTINCT làm băng trợ trên nhu cầu bán tham gia: không quá tuyệt vời. – ErikE

2

Một vấn đề là đi qua mảng hoặc danh sách các loại được chọn vào máy chủ. Chủ đề được bao phủ bởi Eland Sommarskog trong loạt bài báo Arrays and Lists in SQL Server. Việc chuyển danh sách dưới dạng chuỗi được phân cách bằng dấu phẩy và tạo bảng tạm thời là một tùy chọn. Có các lựa chọn thay thế, như sử dụng XML, hoặc Tham số Bảng-Giá trị (trong SQL Server 2008) hoặc sử dụng một bảng @variable thay vì một bảng #temp. Những ưu và khuyết điểm của từng được đề cập trong (các) bài báo tôi đã liên kết.

Làm cách nào để truy xuất sản phẩm. Điều đầu tiên đầu tiên: nếu tất cả các loại được chọn, sau đó sử dụng một truy vấn khác mà chỉ đơn giản là truy xuất tất cả các sản phẩm w/o làm phiền với tất cả các danh mục. Điều này sẽ tiết kiệm được hiệu suất và xem xét rằng tất cả người dùng có thể sẽ thấy trang đầu tiên bất kỳ danh mục nào được bỏ chọn, tiết kiệm có thể đáng kể.

Khi danh mục được chọn, sau đó tạo truy vấn tham gia sản phẩm, danh mục và danh mục được chọn khá dễ dàng. Làm cho nó quy mô và thực hiện là một chủ đề khác nhau, và hoàn toàn phụ thuộc vào lược đồ dữ liệu của bạn và mô hình thực tế của các loại được chọn. Một cách tiếp cận ngây thơ là như thế này:

select ... 
from Products p 
where p.IsEnabled = 1 
and exists (
    select 1 
    from ProductCategories pc 
    join #selectedCategories sc on sc.CategoryID = pc.CategoryID 
    where pc.ProductID = p.ProductID); 

Các ProductsCategoriestable phải có một chỉ mục trên (ProductID, CategoryID) và một trên (CategoryID, ProductID) (một trong số đó là các cụm, một là NC). Điều này đúng cho mọi giải pháp btw. Truy vấn này sẽ hoạt động nếu hầu hết các danh mục luôn được chọn và kết quả chứa hầu hết các sản phẩm hầu hết là. Nhưng nếu danh sách các loại được lựa chọn là hạn chế sau đó là tốt hơn để tránh quá trình quét trên bàn Sản phẩm có tiềm năng lớn và bắt đầu từ các loại lựa chọn:

with distinctProducts as (
select distinct pc.ProductID 
from ProductCategories pc 
join #selectedCategories sc on pc.CategoryID = sc.CategoryID) 
select p.* 
from Products p 
join distinctProducts dc on p.ProductID = dc.ProductID; 

Một lần nữa, giải pháp tốt nhất phụ thuộc chủ yếu vào hình dạng của dữ liệu của bạn. Ví dụ: nếu bạn có danh mục rất bị lệch (một phân loại duy nhất bao gồm 99% sản phẩm) thì giải pháp tốt nhất sẽ phải tính đến độ lệch này.

+0

BTW Tôi giả định từ giải thích rằng kết quả phải phù hợp với * bất kỳ * loại nào (ít nhất một). Như đã chỉ ra khác, là một vấn đề khác nhau nếu sản phẩm phải phù hợp với * tất cả * loại. –

1

này được tất cả sản phẩm có ít nhất trong tất cả các loại mong muốn (không ít hơn):

select * from product p1 join (
    select p.product_id from product p 
    join ProductCategory pc on pc.product_id = p.product_id 
    where pc.category_id in (3,5,8,12) 
    group by p.product_id having count(p.product_id) = 4 
) p2 on p1.product_id = p2.product_id 

4 là số chủng loại trong bộ này.

này được tất cả sản phẩm có chính xác trong tất cả các loại mong muốn (không hơn, không kém):

select * from product p1 join (
    select product_id from product p1 
    where not exists (
    select * from product p2 
    join ProductCategory pc on pc.product_id = p2.product_id 
    where p1.product_id = p2.product_id 
    and pc.category_id not in (3,5,8,12) 
) 
    group by product_id having count(product_id) = 4 
) p2 on p1.product_id = p2.product_id 

Các âm đôi có thể được đọc như: nhận được tất cả các sản phẩm mà có không có danh mục là không trong danh sách danh mục mong muốn.

Đối với các sản phẩm trong bất kỳ các loại mong muốn, nó đơn giản như:

select * from product p1 where exists (
    select * from product p2 
    join ProductCategory pc on pc.product_id = p2.product_id 
    where 
    p1.product_id = p2.product_id and 
    pc.category_id in (3,5,8,12) 
) 
+0

Tôi KHÔNG thích sử dụng IN khi những gì bạn thực sự muốn nói là THAM GIA. Chắc chắn, trình tối ưu hóa đủ thông minh để chuyển đổi nó thành một JOIN trong các trường hợp * nhiều nhất thay vì mở rộng nó thành một mệnh đề OR, nhưng dựa vào đó, tốt, một phím tắt không đáng tin cậy, gần như là một hack. – ErikE

+0

@Emtucifor: Tôi đồng ý! Vì các truy vấn bên trong là những câu hỏi quan trọng cho ví dụ này, tôi đã không đặt nhiều suy nghĩ về những cái bên ngoài. Sửa lỗi đó ngay bây giờ. Truy vấn cuối cùng sử dụng "tham gia" tồn tại để nó không tạo ra các hàng trùng lặp. –