动态名称 - 值对上的T-SQL过滤

时间:2009-05-28 20:53:58

标签: sql-server tsql dynamic-data filtering

我将描述我想要实现的目标:

我传递给一个带有名称值对的SP xml,我把它放到一个表变量中,比方说@nameValuePairs。 我需要检索表达式(表)的ID列表,其中包含与名称 - 值对(属性,另一个表)相关联的精确匹配。

这是我的架构:

表达式表 - > (expressionId,attributeId)

属性表 - > (attributeId,attributeName,attributeValue)

使用动态SQL和邪恶游标尝试复杂的东西(虽然有效,但速度很慢),这就是我现在所拥有的:

--do the magic plz!

-- retrieve number of name-value pairs
SET @noOfAttributes = select count(*) from @nameValuePairs

select distinct
    e.expressionId, a.attributeName, a.attributeValue
into 
    #temp
from 
    expressions e
join
    attributes a
on
    e.attributeId = a.attributeId
join --> this join does the filtering
    @nameValuePairs nvp
on 
    a.attributeName = nvp.name and a.attributeValue = nvp.value
group by
    e.expressionId, a.attributeName, a.attributeValue

-- now select the IDs I need
-- since I did a select distinct above if the number of matches
-- for a given ID is the same as noOfAttributes then BINGO!
select distinct 
    expressionId
from 
    #temp
group by expressionId
having count(*) = @noOfAttributes 

请人们查看并查看他们是否能发现任何问题?有没有更好的方法呢?

任何帮助表示赞赏!

3 个答案:

答案 0 :(得分:1)

这不是一个糟糕的方法,具体取决于表的大小和索引,包括@nameValuePairs。如果这些行数很高或者变得很慢,你可能最好将@namValuePairs放入临时表中,添加适当的索引,并使用单个查询而不是两个单独的查询。

我注意到你将列放入你未使用的#temp中,排除它们会更快(尽管它会意味着#temp中的重复行)。此外,您的第二个查询在同一列上同时具有“distinct”和“group by”。你不需要两者,所以我会删除“distinct”(可能不会影响性能,因为优化器已经想到了这一点)。

最后,对于expressionid上的聚簇非唯一索引,#temp可能会更快(我假设这是SQL 2005)。您可以在SELECT..INTO之后添加它,但在加载之前添加它通常会更快或更快。这将要求您首先创建#temp,添加集群,然后使用INSERT..SELECT来加载它。

我将添加一个合并查询的示例...好吧,这是将它们合并为单个查询的一种方法(这也应该是2000兼容的):

-- retrieve number of name-value pairs
SET @noOfAttributes = select count(*) from @nameValuePairs

-- now select the IDs I need
-- since I did a select distinct above if the number of matches
-- for a given ID is the same as noOfAttributes then BINGO!
select
    expressionId
from 
    (
        select distinct
            e.expressionId, a.attributeName, a.attributeValue
        from 
            expressions e
        join
            attributes a
        on
            e.attributeId = a.attributeId
        join --> this join does the filtering
            @nameValuePairs nvp
        on 
            a.attributeName = nvp.name and a.attributeValue = nvp.value
    ) as Temp
group by expressionId
having count(*) = @noOfAttributes

答案 1 :(得分:1)

我看到的一个错误是你没有别名为b的表,但你正在使用:a.attributeId = b.attributeId。

尝试修复它,看它是否有效,除非我遗漏了什么。

编辑:我认为你刚刚在你的编辑中解决了这个问题,但它应该是a.attributeId = e.attributeId吗?

答案 2 :(得分:1)

我相信这会满足你想要满足的要求。我不确定它有多漂亮,但它应该有效并且不需要临时表:

SET @noOfAttributes = select count(*) from @nameValuePairs

SELECT e.expressionid
FROM expression e
LEFT JOIN (
           SELECT attributeid
           FROM attributes a
           JOIN @nameValuePairs nvp ON nvp.name = a.Name AND nvp.Value = a.value 
           ) t ON t.attributeid = e.attributeid
GROUP BY e.expressionid
HAVING SUM(CASE WHEN t.attributeid IS NULL THEN (@noOfAttributes + 1) ELSE 1 END) = @noOfAttributes

编辑:在做了一些更多的评估后,我发现了一个问题,其中包含了不应该包含的某些表达式。我已经修改了我的查询以将其纳入帐户。