1

这个很棘手……

Products表 -> 产品有多种颜色..

我想要一个存储过程,它可以带回具有某些颜色的产品..

例如,圣诞帽会有“绿色”和“红色”。我想要所有带有“绿色”和“红色”的产品......不仅仅是“绿色”或“红色”,而是两者都有......

这是我目前所拥有的......

问题

  1. 它带回了具有一种或一种颜色而不是两种颜色的产品。
  2. 重复记录。。

代码:

DECLARE @COLORS VARCHAR(MAX) = 'Red, Green'

SELECT * 
FROM Products p
LEFT JOIN Product_Colors_Bridge b ON b.ProductID = p.ProductID
LEFT JOIN Product_Colors c on c.ID = b.ColorID
CROSS JOIN dbo.SplitString(@COLORS, ',', NULL)
WHERE CHARINDEX(token, Color) <> 0

这个图片...

4

3 回答 3

0

这是 set-within-sets 子查询的示例。我喜欢使用聚合来解决这些问题。这里的代码有点棘手,因为您在字符串中列出颜色。

select pcp.ProductId, p.ProductName
from Product p join
     Product_Colors_Bridge pcb
     on p.id = pcb.ProductId join
     Product_Colors pc
     on pcb.ColorId = pc.Id
group by pcp.ProductId, p.ProductName
having count(distinct (case when charindex(pc.Color, @Colors) > 1 then pc.Color end)) =
       (1 + len(@Colors) - len(replace(@Colors, ',', '')))

关键是having从句。第一部分计算产品在列表中的颜色数量。第二个通过不带逗号的字符串长度差来计算颜色总数。

如果您愿意,您也可以将case条件移到group by-- 假设您不关心其他颜色。

select pcp.ProductId, p.ProductName
from Product p join
     Product_Colors_Bridge pcb
     on p.id = pcb.ProductId join
     Product_Colors pc
     on pcb.ColorId = pc.Id join
     dbo.SplitString(@COLORS, ',', NULL) ssc
     on ssc.token = pc.Color
group by pcp.ProductId, p.ProductName
having count(*) =
       (1 + len(@Colors) - len(replace(@Colors, ',', '')))
于 2013-06-14T16:12:28.933 回答
0

假设您使用的是 SQL-Server 2008 或更高版本,我建议您避免在 SQL 中使用分隔字符串。如果要将多个值作为参数传递,请使用表值参数

所以你首先要让你的类型存储多种颜色(给定一个通用名称,以便它可以重复使用):

CREATE TYPE dbo.StringList AS TABLE (Value NVARCHAR(MAX));

这不应该花费更多的精力来创建参数,但避免了昂贵的(程序)拆分方法,那么您的查询将变为:

DECLARE @Colors dbo.StringList;
INSERT @Colors VALUES ('Red'), ('Green');

SELECT  p.ProductID, p.ProductName
FROM    Products p
        INNER JOIN Product_Colors_Bridge b 
            ON b.ProductID = p.ProductID
        INNER JOIN Product_Colors c 
            ON c.ID = b.ColorID
        INNER JOIN @colors co
            ON co.Value = c.Color
GROUP BY p.ProductID, p.ProductName
HAVING  COUNT(DISTINCT c.Color) = (SELECT COUNT(DISTINCT Value) FROM @Colors);

-- HAVING IS KEY HERE, STATING THAT THE COUNT OF DIFFERENT COLOURS ASSOCIATED 
-- WITH THE PRODUCT IS THE SAME AS THE NUMBER OF DIFFERENT COLOURS PASSED TO
-- THE QUERY IN THE PARAMETER
于 2013-06-14T16:22:57.987 回答
0

这是使用以下方法执行此操作的简单方法like

declare @colors varchar(max) = 'Red,Green'; 

select p.ProductID, p.ProductName
from Products p
    join Product_Colors_Bridge b on b.ProductID = p.ProductID
    join Product_Colors c on c.ID = b.ColorID
where ',' + @colors + ',' like '%,' + c.Color + ',%'
group by p.ProductID, p.ProductName
having count(*) = len(@colors) - len(replace(@colors, ',', '')) + 1;

/*
  ProductID ProductName
----------- --------------
          2 Santa Hat
*/

这将获得在您的搜索字符串中至少包含所有颜色的所有产品。

请注意,我已删除搜索字符串中的空格,并添加逗号(在查询本身中)以通过搜索“Blue”来消除“BabyBlue”匹配的可能性。我还假设您的表格或搜索字符串中没有重复的颜色或颜色分配。

您必须在您的环境中进行测试,以查看此技术是否比使用 UDF 进行拆分或以不同方式传递参数(XML、表值参数)更快。也就是说,我通常会远离数据库中的分隔字符串(尽管我们没有将它们存储在这里,这是一个滑坡到无处可去的地方)并且宁愿使用 TVP 或在您的应用程序中动态创建查询(使用参数,而不是动态 SQL)如果可能的话(这可以利用索引)。

于 2013-06-14T16:44:22.143 回答