SQL Server:查找每个用户购买的最受欢迎的产品类别,以便在子查询中使用

时间:2014-07-30 14:57:44

标签: sql sql-server

我有三个表:categories(id,name),products(id,category_id,name))和purchases(id,user_id,product_id)。 product属于category。用户可以购买许多products。我的目的是找到每个用户最受欢迎的category

但是,我需要将查询的结果集用作子查询,因此由于SQL Server限制(可怕的ORDER BY错误),遗憾的是使用任何The ORDER BY clause is invalid in views, inline functions, derived tables, and subqueries, unless TOP is also specified.语句都是关闭的。

我的方法是为每个用户purchases创建一个所有category的列表。然后我有一个MAX函数来挑选purchases的最大数量。我将结果连接到原始查询(作为子查询复制)以检索有问题的category_id,最后我获取类别名称。

我的查询有两个问题:

  1. 显然我不希望在我的代码中两次使用相同的查询。但是,我不能依赖于使用CTE或临时表,因为此查询的结果旨在链接到具有用户数据子集的视图,并且VIEW代码旨在用于第三个-party包,只能处理基本的SQL代码。
  2. 如果出现平局(比较一个使用者买了4 products,每个2 categories就有2个),我最终会为该用户提供一个重复的行。
  3. 小提琴:

    http://sqlfiddle.com/#!6/8821b/5

    如果有人能够帮助我找到确保每个用户只返回一行的方法,以及删除重复的子查询的方法,我将不胜感激。

    谢谢!

1 个答案:

答案 0 :(得分:5)

首先,感谢您在SQLFiddle中提供示例。它使ALOT变得更容易。

您可以使用row_number更精确地获取" top"记录。在这个例子中,我选择在计数后使用category_name作为辅助排序标准。

SELECT user_id, category_name, category_count
FROM
(
  SELECT 
      user_id, COUNT(1) as category_count, category_name, 
      ROW_NUMBER() OVER (
          PARTITION BY user_id 
          ORDER BY COUNT(1) DESC, category_name ASC) 
          as ordinal_position
  FROM
      purchases p 
          JOIN products p2 ON p.product_id = p2.id
          JOIN categories c ON p2.category_id = c.id        
  GROUP BY user_id, category_name
 ) a
WHERE ordinal_position = 1
ORDER BY category_count DESC

Example at SQL Fiddle.