因此,假设您有一个Products表(ID int,Name nvarchar(200))和另外两个表ProductsCategories(ProductID int,CategoryID int)和InvoiceProducts(InvoiceID int,ProductID int).
我需要编写一个查询来生成一组与一组给定的发票ID和类别ID匹配的产品,这样产品列表就可以匹配所有指定的类别和所有指定的发票,而不会回退到动态sql.想象一下,我需要找到1类和2类以及发票3和4中的产品列表.
首先,我编写了一个存储过程,将类别ID和发票ID作为字符串接受,并将它们解析为表格:
- CREATE PROCEDURE dbo.SearchProducts (@categories varchar(max),@invoices varchar(max))
- AS BEGIN
- with catids as (select cast([value] as int) from dbo.split(@categories,' ')),invoiceids as (select cast([value] as int) from dbo.split(@invoices,' '))
- select * from products --- insert awesomeness here
- END
我提出的不同解决方案看起来很糟糕,而且表现更差.我发现的最好的事情是生成一个由所有条件的左连接组成的视图,但这似乎非常昂贵,并没有解决匹配指定的所有不同键的问题.
更新:这是我编写的一个示例查询,可以产生预期的结果.我错过了任何优化机会吗?像忍者的魔法独角兽矩阵操作一样?
- with catids as (select distinct cast([value] as int) [value] from dbo.split(@categories,invoiceids as (select distinct cast([value] as int) [value] from dbo.split(@invoices,' '))
- select pc.ProductID from ProductsCategories pc (nolock)
- inner join catids c on c.value = pc.CategoryID
- group by pc.ProductID
- having COUNT(*) = (select COUNT(*) from catids)
- intersect
- select ip.ProductID from InvoiceProducts ip (nolock)
- inner join invoiceids i on i.value = ip.InvoiceID
- group by ip.ProductID
- having COUNT(*) = (select COUNT(*) from invoiceids)
解决方法
如果您在(ProductID,CategoryID)和(ProductID,InvoiceID)上都有唯一索引:
- SELECT ProductID
- FROM (
- SELECT ProductID
- FROM ProductInvoice
- WHERE InvoiceID IN (1,2)
- UNION ALL
- SELECT ProductID
- FROM ProductCategory pc
- WHERE CategoryID IN (3,4)
- ) q
- GROUP BY
- ProductID
- HAVING COUNT(*) = 4
或者,如果您的值以CSV字符串传递:
- WITH catids(value) AS
- (
- SELECT DISTINCT CAST([value] AS INT)
- FROM dbo.split(@categories,' '))
- ),(
- SELECT DISTINCT CAST([value] AS INT)
- FROM dbo.split(@invoices,' '))
- )
- SELECT ProductID
- FROM (
- SELECT ProductID
- FROM ProductInvoice
- WHERE InvoiceID IN
- (
- SELECT value
- FROM invoiceids
- )
- UNION ALL
- SELECT ProductID
- FROM ProductCategory pc
- WHERE CategoryID IN
- (
- SELECT value
- FROM catids
- )
- ) q
- GROUP BY
- ProductID
- HAVING COUNT(*) =
- (
- SELECT COUNT(*)
- FROM catids
- ) +
- (
- SELECT COUNT(*)
- FROM invoiceids
- )
请注意,在sql Server 2008中,您可以将表值参数传递到存储过程中.