我有一个在线商店,正试图在产品页面上显示五种类似的产品。产品和标签之间有一种多对多的关系,我正试图使用INNER JOIN
来查询(联接表(。以下是我迄今为止的SQL查询:
SELECT TOP(5) *
FROM [Store_ProductTags] AS [s]
INNER JOIN [Store_Products] AS [s0] ON [s].[ProductId] = [s0].[Id]
ORDER BY CASE WHEN TagId IN (1, 17) THEN 0 ELSE 1 END;
它做了我想要的(即获得五个与正在显示的产品具有相同标签的产品(,然而,包括重复。。。
这是我得到的结果(注意ProductId为1的两条记录(:
ProductId TagId Name
10 17 Harlots - The Woman You Saw... (CD)
1 1 Unholy - Blood of the Medusa (CD)
44 1 Unholy - Blood of the Medusa (LP)
1 2 Unholy - Blood of the Medusa (CD)
2 2 Lye By Mistake - Arrangements for Fulminating Vective (CD)
我想排除重复项。到目前为止,我已经尝试了DISTINCT
和GROUP BY
,正如不同问题中的其他回答所显示的那样,但都无济于事。当我在SELECT
之后添加DISTINCT
时,我收到的错误是…
有什么建议吗?
您可以按产品分组,并根据匹配标签的数量对结果进行排序:
SELECT TOP(5) p.Id, p.Name
FROM Store_Products AS p INNER JOIN Store_ProductTags AS s
ON s.ProductId = p.Id
GROUP BY p.Id, p.Name
ORDER BY SUM(CASE WHEN s.TagId IN (1, 17) THEN 1 ELSE 0 END) DESC;
如果我正确理解,您可以将逻辑移动到order by
子句中的子查询:
select top (5) p.*
from store_products p
order by
case when exists (
select 1
from store_producttags pt
where pt.productid = p.id and pt.tagid in (1, 17)
)
then 0
else 1
end
这将选择5种产品,并将优先权授予拥有2个搜索标签的产品。
如果没有这样的标记,您的代码可以返回五个与任何标记都不匹配的产品。我不知道这是一个功能还是一个bug。根据查询的描述,这听起来像是一个bug。
你想要每个产品id一行。我猜你真的不需要匹配的标签。如果没有,最简单的方法是使用IN
或EXISTS
:过滤出不匹配的产品
SELECT TOP(5) sp.*
FROM Store_Products sp
WHERE EXISTS (SELECT 1
FROM Store_ProductTags spt
WHERE spt.[ProductId] = s.[Id] AND
spt.TagId IN (1, 17)
);