【问题标题】:SQL To Find Most Popular CategorySQL 查找最受欢迎的类别
【发布时间】:2009-06-27 01:45:53
【问题描述】:

我的数据库 (MySQL) 中有 3 个表。

categories (name:string)
items (name:string, category_id:int)
votes (value:int, item_id:int, created_at:datetime)

所以一个类别有很多项目,一个项目有很多票。

我想编写一个查询来获取最受欢迎的类别,这意味着获取上周获得最多票数(无论是上还是下)的类别。

我开始尝试一些更简单的东西,只是获得受欢迎的物品,但我现在真的只是在猜测,它不起作用。

SELECT *, COUNT(votes.item_id) AS score
FROM items
JOIN votes USING(item_id)
WHERE votes.created_at > #{1.week.ago}
ORDER BY COUNT(votes.item_id) DESC LIMIT 5;

我真的不知道我在做什么,有什么想法吗?另外,如果有人知道这样的更高级选择的好文章,我很乐意阅读。 MySQL 文档有点神秘,我不太了解“AS”和“JOINS”。

【问题讨论】:

    标签: sql mysql


    【解决方案1】:

    试试这个。使用 group by 与类别的名称。我已经按照您的说明将创建的 at 子句注释掉了,如果您想使用它可以取消注释。

     SELECT c.name, SUM(ABS(v.item_id)) 
     FROM categories c,items i, votes v
     WHERE c.name = i.name
        AND i.item_id=v.item_id
        --AND v.created_at > #{1.week.ago}
     GROUP BY c.name 
     ORDER BY SUM(ABS(v.item_id)) DESC LIMIT 5;
    

    您会注意到我没有使用 JOIN 关键字,而是仅使用 WHERE 子句过滤了查询结果,这可能更容易理解。如果你想了解更多关于 JOIN 的信息,here is a tutorial

    Here, too, is a tutorial on SQL aliases(AS 子句)。事实上,在这个网站上还有很多关于不同平台的不同 SQL 主题的教程。

    编辑:按照cmets修复,添加abs函数,

    【讨论】:

      【解决方案2】:

      在这种情况下,您可能可以使用 group by 并删除连接。我在使用 group by 时总是搞砸了,但是像

      SELECT COUNT(votes.item_ID) AS score, 
        (SELECT ItemTitle FROM items WHERE items.item_id = votes.item_id) as Title
      FROM votes
      WHERE votes.created_at > #{1.week.ago}
      Group By Title
      Order By score
      Limit 5
      

      AS

      "as" 允许您给某物命名。

      注意上面的 as score,这给 count(votes.item_id) 的结果提供了 score 的列名,因为它之前没有列名。如果您想在查询的其余部分用另一个名称调用某些东西,也可以使用它。

      如果您取消 as 分数,它将作为没有标题的列返回,并且无法通过名称访问它,只能通过数字访问它。

      加入

      连接会将 2 个表合并为 1 个临时表并返回此表。有内连接、外连接、左连接、右连接和交叉连接。每个都有自己的优点,但都有一个慢的问题。查看子查询以替换大多数连接。

      您还需要避免使用 Select *,列出您需要的所有内容。

      解决这些问题的最佳方法是运行它们并查看它们返回的内容并阅读它们应该做什么w3Schools Joins

      【讨论】:

      • count 应该是 sum,正如@Paul Chernoch 所指出的,abs 可能是值得的
      【解决方案3】:

      这是在 SQL Server 中...但对于我认为的 MySQL 人来说很容易转换!

      select top 5
          c.name as CategoryName, sum(v.value) as VoteSum
      from categories c inner join items i
          on c.category_id = i.category_id
          inner join votes v
              on i.item_id = v.item_id
      where created_at between dateadd(week,-1,getdate()) and getdate()
      group by c.name
      order by sum(v.value) desc
      

      选择前 5 个--计算中显示的类别数

      c.name as CategoryName, sum(v.value) as VoteSum --获取categoryname和投票总和

      from categories c inner join items i --join the heirarchy: categories to items

      关于 c.category_id = i.category_id --关于 category_id

      inner join votes v --要投票的项目

      关于 i.item_id = v.item_id --关于 item_id

      dateadd(week,-1,getdate()) 和 getdate() 之间的 created_at --指定要包含的日期范围

      按c.name分组--按类别分组结果

      order by sum(v.value) desc --按求和值排序

      这里有一些 sql(来自 SQL Server)来启动和运行表:

      CREATE TABLE [categories](
          [category_id] [int] IDENTITY(1,1) NOT NULL,
          [name] [varchar](50) NOT NULL
      )
      
      CREATE TABLE [items](
      [item_id] [int] IDENTITY(1,1) NOT NULL,
      [category_id] [int] NOT NULL,
      [name] [varchar](50)
      )
      
      CREATE TABLE [dbo].[votes](
      [vote_id] [int] IDENTITY(1,1) NOT NULL,
      [value] [int] NOT NULL,
      [item_id] [int] NOT NULL,
      [created_at] [datetime] NOT NULL
      )
      
      insert into categories (name) values (' asp.net ')
      insert into categories (name) values (' c#  ')
      insert into categories (name) values (' vb  ')
      insert into categories (name) values (' sql ')
      insert into categories (name) values (' html    ')
      insert into categories (name) values (' javascript  ')
      
      insert into items (category_id, name) values (  1   ,'  session handling    ')
      insert into items (category_id, name) values (  1   ,'  mvc vs mvp  ')
      insert into items (category_id, name) values (  1   ,'  code behind or no code behind   ')
      insert into items (category_id, name) values (  2   ,'  LINQ?   ')
      insert into items (category_id, name) values (  2   ,'  lamdas  ')
      insert into items (category_id, name) values (  2   ,'  multi-threaded code ')
      insert into items (category_id, name) values (  2   ,'  SOLID principles    ')
      insert into items (category_id, name) values (  3   ,'  vb vs C#    ')
      insert into items (category_id, name) values (  3   ,'  VB.NET over vb6 ')
      insert into items (category_id, name) values (  4   ,'  CLR procedures or stored procedures ')
      insert into items (category_id, name) values (  4   ,'  ORMs vs stored procedures and views ')
      insert into items (category_id, name) values (  6   ,'  jquery instead of standard DOM  ')
      
      insert into votes (value, item_id, created_at) values ( -1  ,   1   ,'  6/26/2009 18:59 ')
      insert into votes (value, item_id, created_at) values ( 1   ,   1   ,'  6/26/2009 18:59 ')
      insert into votes (value, item_id, created_at) values ( 3   ,   1   ,'  6/26/2009 18:59 ')
      insert into votes (value, item_id, created_at) values ( 3   ,   1   ,'  6/26/2009 18:59 ')
      insert into votes (value, item_id, created_at) values ( 2   ,   2   ,'  6/26/2009 18:59 ')
      insert into votes (value, item_id, created_at) values ( 2   ,   2   ,'  6/26/2009 18:59 ')
      insert into votes (value, item_id, created_at) values ( 4   ,   2   ,'  6/26/2009 18:59 ')
      insert into votes (value, item_id, created_at) values ( -3  ,   2   ,'  6/26/2009 18:59 ')
      insert into votes (value, item_id, created_at) values ( 2   ,   4   ,'  6/26/2009 19:00 ')
      insert into votes (value, item_id, created_at) values ( 6   ,   4   ,'  6/26/2009 19:00 ')
      insert into votes (value, item_id, created_at) values ( 3   ,   4   ,'  6/26/2009 19:00 ')
      insert into votes (value, item_id, created_at) values ( 5   ,   4   ,'  6/26/2009 19:00 ')
      insert into votes (value, item_id, created_at) values ( 8   ,   7   ,'  6/26/2009 19:00 ')
      insert into votes (value, item_id, created_at) values ( 3   ,   6   ,'  6/26/2009 19:00 ')
      insert into votes (value, item_id, created_at) values ( 8   ,   7   ,'  6/26/2009 19:01 ')
      insert into votes (value, item_id, created_at) values ( 2   ,   5   ,'  6/26/2009 19:01 ')
      

      【讨论】:

      • 他指定mysql,TOP 5不是sql server构造吗?
      • ye top 是 mssql。把前5个去掉,在底部加上limit 5就行了。
      【解决方案4】:

      1) 我假设 categories 表也有 category_id 字段,并且 items 表有 item_id 否则您将无法链接这些表。 2) AS 关键字通常是可选的

      SELECT c.name, SUM(ABS(v.value))
      FROM categories c
      INNER JOIN items i ON c.category_id = i.category_id
      INNER JOIN votes v ON v.item_id = i.item_id
      WHERE v.created_at BETWEEN DATE_SUB(NOW(), INTERVAL -7  DAYS) AND NOW()
      GROUP BY c.name
      ORDER BY 2 DESC
      LIMIT 10
      
      • AS 关键字用于制作表名的同义词。大多数情况下,这只是一种简写,但如果您在表连接到自身的地方执行自连接,则需要区分它们。而如果两个表的字段名相同,则需要指定使用的是哪个表的字段,因此c.category_id来自“c”表,即类别表。
      • 联接是必不可少的。开始阅读。
      • 在我的解决方案中,我使用了 mySQL 原生的 DATE_SUB。我不知道有多少其他数据库使用该功能,但它们都有类似的东西。
      • 我的查询为您提供了最受欢迎的前十个类别。请注意,LIMIT N 子句是您在 mySQL 中的操作方式。在 SQLServer 中,在 SELECT 关键字之后使用 TOP N。在 Oracle 中,它以另一种方式完成。
      • 我采用了选票的绝对值,因为您说包括赞成票或反对票。
      • ORDER BY 2 DESC 表示按选择中的第二列降序排序。您可以在此处使用实际表达式,但这需要更多的输入。
      • GROUP BY 是必需的。如果使用了任何聚合函数,则每一个不是常量或与 SUM、COUNT、MAX 等聚合的列都必须出现在 GROUP BY 子句中。

      【讨论】:

      • 关于 Oracle 中的 TOP/LIMIT 等价物:它是 ROWNUM 和 ROWNUM
      【解决方案5】:
      SELECT c.name, sum(v.value) as cnt
       FROM categories c
       JOIN items i ON i.category_id = c.id
       JOIN votes v ON v.item_id = i.id
       WHERE v.created_at > #{1.week.ago}
       GROUP BY c.name 
       ORDER BY cnt DESC LIMIT 5;
      

      编辑:好点安德鲁,我修复了查询

      【讨论】:

      • 这没有考虑投票的价值可能大于一……或负值的想法
      【解决方案6】:

      这就是我最终使用的(@akf 答案的略微修改版本)。其他答案也很棒,但对于我这个新手来说,这似乎是最简单的。我觉得它不使用任何连接很有趣?不会想到这是可能的。我喜欢它的干净和简单。

      SELECT c.*, SUM(ABS(v.vote)) AS score
      FROM categories c,items i, votes v
        WHERE c.id = i.category_id
        AND i.id = v.item_id
        AND v.created_at > '#{1.week.ago}'
      GROUP BY c.id
      ORDER BY score DESC LIMIT 5;
      

      (我忘了在问题中提到每个表都有一个“id”列,您可以在此处看到正在使用的列。)

      在这种情况下,对投票值的绝对值求和是有效的,因为正如一些张贴者正确指出的那样,有正面和负面,但我认为只计算数据库中的投票记录数会更简单。我尝试了“COUNT(v) AS score”,但这没有用。如果有人知道如何发表评论。谢谢大家!

      【讨论】:

      • 我认为这个查询仍然被认为是一个 JOIN 查询,但是有快捷方式。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-20
      • 2021-04-08
      • 2012-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多