【问题标题】:Select The last 3 news from each category - Two tables - (MySQL - PHP)选择每个类别的最后 3 条新闻 - 两个表 - (MySQL - PHP)
【发布时间】:2018-12-25 18:21:28
【问题描述】:

我想从两个表中选择每个类别的最后 3 条新闻

first table ' Categories ' & ' news '

分类表

ID_CAT | NAME | PRIORITE

新闻表

ID | ID_CAT | TITLE | THE_NEWS

我尝试在此 SQL 代码中进行限制,但它只给了我所有类别的最后 3 条新闻

SELECT C.PRIORITE, N.* 
  FROM categories C, news N 
 WHERE N.ID_CAT=C.ID_CAT 
   AND C.PRIORITE >1 
ORDER BY N.ID DESC 
LIMIT 3

我尝试获取所有具有PRIORITE > 1 的新闻(优先级是类别的顺序)所以,我想从每个优先级中获​​取 3 个最新消息。

例子:

Priorite 2 = get last 3 news
Priorite 3 = get last 3 news 

...等

我在互联网上进行了一些搜索,但对我没有任何帮助,有什么解决方案吗?还是我需要创建另一个函数来获取每个类别的新闻,并在其参数中发送 ID?

【问题讨论】:

  • 为了帮助解决查询问题,我们需要查看:具有列和类型的表、用于输入的示例数据、您想要的输出、您现在通过查询获得的输出。
  • @Nic3500 感谢您的回复先生,我修改了帖子
  • 我的直觉是将其放入 foreach($categories as $category) 循环中,但这可能/最终会相当密集和漫长。可能有一种方法可以更快地使用子查询。据我所知,“最好”的方法是有一个“全部”页面,然后是“类别”页面来规避这一点。
  • @Joshua 感谢您的回复先生,我避免创建另一个函数,因为这会使响应时间更长,为此我想进行一个简单的查询

标签: php mysql greatest-n-per-group


【解决方案1】:

试试这个查询。此查询根据优先级为每条记录生成一个行号。然后返回行号等于或小于 3。

SELECT ID, PRIORITE, THE_NEWS
FROM
(
   SELECT ID, PRIORITE, THE_NEWS  ,
   @rn := IF(@prior = PRIORITE, @rn + 1, 1) AS rn,
   @prior := PRIORITE 
   FROM(
   SELECT t.*,c.PRIORITE FROM news t 
   LEFT JOIN categories c ON t.ID_CAT=c.ID_CAT ) e
   CROSS JOIN (select @rn:=0, @prior:=null) c
   ORDER BY  PRIORITE,ID desc
) as x 
WHERE x.rn <= 3 ;

【讨论】:

    【解决方案2】:

    我建议把它分成两部分,而不是复杂的查询,

    在第一部分你可以得到类别

    select * from Categories
    

    然后循环分类并在循环中得到他们的 3 个新闻,

    select * from news where cat_id = '' order by desc id limit 3
    

    如果您同时尝试并检查执行时间,您会发现循环花费的时间更少。因为新闻是快速增长的东西。我知道你认为我为什么一次又一次地调用查询,但我的老师说更喜欢多个查询而不是复杂的查询

    【讨论】:

    【解决方案3】:

    你可以得到 n 不。每个类别的新闻使用相关子查询

    SELECT *
    FROM news n
    JOIN categories c ON c.id = n.category_id
    WHERE c.priority > 1
    AND (
      SELECT COUNT(*)
      FROM news 
      WHERE n.category_id = category_id
      AND n.id <= id
    ) <= 3; 
    

    Demo

    或者,如果您使用的是 Mysql 8,那么您可以使用 window functionscommon table expressions 之类的

    WITH cte AS(
        SELECT *, 
        RANK() OVER (PARTITION BY category_id ORDER BY id DESC ) rnk
        FROM news
        ORDER BY id
    
    )
    
    SELECT *
    FROM cte n
    JOIN categories c ON c.id = n.category_id
    WHERE c.priority > 1
    AND rnk <= 3;
    

    Demo

    【讨论】:

      【解决方案4】:

      试试这个查询,它应该可以工作:

      SELECT
          C.PRIORITE, N.*
      FROM
          categories C
      JOIN news N ON N.ID_CAT=C.ID_CAT
      AND C.PRIORITE >1 
      GROUP BY
          C.ID_CAT
      HAVING
          COUNT(*) <= 3
      ORDER BY N.ID DESC
      

      让我知道这是否有任何问题。

      【讨论】:

      • 谢谢您的回复先生,我试了一下,结果是零行
      • 我看到您将列名更改为 ID_CAT,我希望这不是问题。我更新了上面的查询。尝试一次。
      • 不先生不是问题,因为我在尝试查询后进行了编辑,当我删除这一行HAVING COUNT(*) &lt;= 3时,结果是每个类别的一行
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-18
      • 2015-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-09
      相关资源
      最近更新 更多