我正在构建一个查询,该查询用于Items
根据 selected生成索引页面,通过计算过去 24 小时内将项目添加到 a 的次数和次数,Category
按相对受欢迎程度排序。查询的单个输入是主要类别 ID。Likes
List
这涉及到总共 4 个表,其中一个是嵌套集,所以它并不完全是微不足道的。我通常非常擅长编写相当有效的 SQL,但我很难让 JOIN 以我想要的方式工作。
类别
由于类别是嵌套的并且项目被分配给单个类别,因此有必要首先选择查询输入中位于指定类别之下的所有类别。
我正在使用awesome_nested_set gem 来完成这项工作。它添加了lft
和rgt
列,可用于从层次结构中毫无困难地进行选择:
SELECT c2.*
FROM categories c1
JOIN categories c2
ON c2.lft >= c1.lft AND c2.rgt <= c1.rgt
WHERE c1.id = [MAIN CATEGORY ID]
项目
然后扩展上述内容以选择项目非常简单:
SELECT i.*
FROM categories c1
JOIN categories c2
ON c2.lft >= c1.lft AND c2.rgt <= c1.rgt
JOIN items i
ON i.category_id = c2.id
WHERE c1.id = [MAIN CATEGORY ID]
到目前为止,一切工作正常且执行迅速。最后要做的事情(当然忽略分页)是订购它们。
人气
项目按受欢迎程度排序。计算一个项目的受欢迎程度的方法是:
(number of likes) + (number of times added to list) * 5
例如,如果一个项目已被添加到 32 个列表并被点赞 483 次,那么受欢迎度指标将为 643。
根据用户是查看“所有时间最受欢迎”还是“趋势”,我们可能会将这些指标的计算限制为过去一天发生的喜欢/列表。
我认为这将是相对微不足道的,但最终并非如此。COUNT
当您与 s 一起使用时显然会出现问题,JOIN
我需要使用 LEFT JOIN 以防项目有 0 个喜欢/列表。
当前工作代码如下:
SELECT
q.*,
(q.likes + q.lists * 5) AS popularity
FROM
(
SELECT
i.*,
(SELECT COUNT(*) FROM likes l WHERE i.id = l.item_id AND l.created_at > DATE_SUB(NOW(), INTERVAL 1 day)) AS likes,
(SELECT COUNT(*) FROM list_items li WHERE i.id = li.item_id AND li.created_at > DATE_SUB(NOW(), INTERVAL 1 day)) AS lists
FROM categories c1
JOIN categories c2
ON c2.lft >= c1.lft AND c2.rgt <= c1.rgt
JOIN items i
ON i.category_id = c2.id
WHERE c1.id = 37
) q
ORDER BY popularity
然而,这显然是非常可怕的代码。每个项目都需要进行两个子查询,然后整个事情都需要被包装以进行一些算术运算(尽管我认为这还不错)。
我尝试了以下事情,但由于各种原因它们没有奏效:
SELECT
i.*,
(SELECT COUNT(*) FROM likes l WHERE i.id = l.item_id AND l.created_at > DATE_SUB(NOW(), INTERVAL 1 day)) AS likes,
(SELECT COUNT(*) FROM list_items li WHERE i.id = li.item_id AND li.created_at > DATE_SUB(NOW(), INTERVAL 1 day)) AS lists,
(likes + lists * 5) AS popularity
出于某种原因,您无法对您选择的其他列进行数学运算。
SELECT
i.*,
COUNT(l.id) as likes,
COUNT(li.id) as lists
FROM categories c1
JOIN categories c2
ON c2.lft >= c1.lft AND c2.rgt <= c1.rgt
JOIN items i
ON i.category_id = c2.id
LEFT JOIN likes l
ON l.item_id = i.id
LEFT JOIN list_items li
ON li.item_id = i.id
WHERE c1.id = 37
由于某种原因,您只能得到一个结果。我不明白这是什么原因。
SELECT
i.*,
COUNT(l.id) as likes,
COUNT(li.id) as lists
FROM categories c1
JOIN categories c2
ON c2.lft >= c1.lft AND c2.rgt <= c1.rgt
JOIN items i
ON i.category_id = c2.id
LEFT JOIN likes l
ON l.item_id = i.id
LEFT JOIN list_items li
ON li.item_id = i.id
WHERE c1.id = 37
GROUP BY i.id
添加GROUP BY
使所有项目返回,但喜欢/列表的数字现在完全错误。我认为这是将它们加起来之类的。
基本上,我有点卡住了。上面带有子查询的示例确实有效,但我认为它的工作方式并不理想。我想让它只与JOIN
s 一起工作,但我很难理解如何。
任何帮助深表感谢 :)