假设我有这三个表:
对于所有产品,我想得到的是product_id和最常见的客户(产品的最大客户)。
我解决了这个问题:SELECT
product_id AS product,
(SELECT TOP 1 client_id FROM Bill_Item, Bill
WHERE Bill_Item.product_id = p.product_id
and Bill_Item.bill_id = Bill.bill_id
GROUP BY
client_id
ORDER BY
COUNT(*) DESC
) AS client
FROM Product p
你知道更好的方法吗?
答案 0 :(得分:2)
内部查询将为您提供排名。外部查询将为您提供最适合产品的客户
SELECT *
(
SELECT i.product_id, b.client_id,
r = row_number() over (partition by i.product_id
order by count(*) desc)
FROM Bill b
INNER JOIN Bill_Item i ON b.bill_id = i.bill_id
GROUP BY i.product_id, b.client_id
) d
WHERE r = 1
答案 1 :(得分:1)
松鼠的答案不会归还从未销售过的产品。如果你想包含那些,那么你的方法是可以的,虽然我会把查询写成:
SELECT product_id as product,
(SELECT TOP 1 b.client_id
FROM Bill_Item bi JOIN
Bill b
ON bi.bill_id = b.bill_id
WHERE Bill_Item.product_id = p.product_id
GROUP BY client_id
ORDER BY COUNT(*) DESC
) as client
FROM Product p;
您也可以使用APPLY
来表达这一点,但相关的子查询也可以。
请注意正确使用显式JOIN
语法。
答案 2 :(得分:1)
我只使用Common Table Expression [CTE]而不是派生表提交与@Squirrell几乎相同的内容。所以我不会重复,但有一些关于您的查询的学习点。首先是IMPLICIT JOINS
,例如FROM Bill_Item, Bill
很容易产生意想不到的后果(很多问题之一:Queries that implicit SQL joins can't do?)接下来,对于计算列,您实际上可以在OUTER APPLY
中执行此操作或CROSS APPLY
这是一种非常有用的技术。
所以你可以按如下方式重写你的方法:
SELECT *
FROM
Product p
OUTER APPLY (SELECT TOP 1 b.client_id
FROM
Bill_Item bi
INNER JOIN Bill b
ON bi.bill_id = b.bill_id
WHERE
bi.product_id = p.product_id
GROUP BY
b.client_id
ORDER BY
COUNT(*) DESC) c
为了向您展示squirell的答案如何仍然包括从未销售过的产品,您只需将产品和LEFT JOIN加入其他表:
;WITH cte AS (
SELECT
p.product_id
,b.client_id
,ROW_NUMBER() OVER (PARTITION BY p.product_id ORDER BY COUNT(*) DESC) as RowNumber
FROM
Product p
LEFT JOIN Bill_Item bi
ON p.product_id = bi.product_id
LEFT JOIN Bill b
ON bi.bill_id = b.bill_id
GROUP BY
p.product_id
,b.client_id
)
SELECT *
FROM
cte
WHERE
RowNumber = 1
其中一些有用的技术。