重写MySQL查询

重写MySQL查询,sql,mysql,subquery,limit,Sql,Mysql,Subquery,Limit,我将试着在另一个问题上更好地解释这一点。这是我认为应该可以使用的查询,但MySQL不支持这种特定的子选择查询: select * from articles a where a.article_id in (select f.article_id from articles f where f.category_id = a.category_id order by f.is_sticky, f.published_at

我将试着在另一个问题上更好地解释这一点。这是我认为应该可以使用的查询,但MySQL不支持这种特定的子选择查询:

select *
  from articles a
  where a.article_id in
      (select f.article_id
        from articles f
        where f.category_id = a.category_id
        order by f.is_sticky, f.published_at
        limit 3) /* limit isn't allowed inside a IN subquery */
我试图归档的是:在一个articles表中,我有几个类别的文章。我需要获得每个类别最多三篇文章(任意数量的类别)

以下是数据:

CREATE TABLE articles (
  article_id int(10) unsigned NOT NULL AUTO_INCREMENT,
  category_id int(10) unsigned NOT NULL,
  title varchar(100) NOT NULL,
  is_sticky boolean NOT NULL DEFAULT 0,
  published_at datetime NOT NULL,
  PRIMARY KEY (article_id)
);

INSERT INTO articles VALUES
(1, 1, 'foo', 0, '2009-02-06'),
(1, 1, 'bar', 0, '2009-02-07'),
(1, 1, 'baz', 0, '2009-02-08'),
(1, 1, 'qox', 1, '2009-02-09'),

(1, 2, 'foo', 0, '2009-02-06'),
(1, 2, 'bar', 0, '2009-02-07'),
(1, 2, 'baz', 0, '2009-02-08'),
(1, 2, 'qox', 1, '2009-02-09');
我试图检索的内容如下:

1, 1, qox, 1, 2009-02-09
1, 1, foo, 0, 2009-02-06
1, 1, bar, 0, 2009-02-07
1, 2, qox, 1, 2009-02-09
1, 2, foo, 0, 2009-02-06
1, 2, bar, 0, 2009-02-07
注意“quox”是如何跃居其类别的第一位的,因为它是粘性的

您能想出一种方法来避免子查询中的限制吗

谢谢

我找到了一个(可怕的,可怕的)解决方法,我甚至不应该发布它,但是

select *
  from articles a
  where a.article_id =
      (select f.article_id
        from articles f
        where f.category_id = a.category_id
        order by f.is_sticky, f.published_at
        limit 1)
union
select *
  from articles a
  where a.article_id =
      (select f.article_id
        from articles f
        where f.category_id = a.category_id
        order by f.is_sticky, f.published_at
        limit 1, 1)
union
select *
  from articles a
  where a.article_id =
      (select f.article_id
        from articles f
        where f.category_id = a.category_id
        order by f.is_sticky, f.published_at
        limit 2, 1)
order by category_id
因为我每个类别只需要三篇文章,所以我可以重复查询三次(而不是每个类别重复查询),一次用于所有类别中的第一篇文章,一次用于所有类别中的第二篇文章,一次用于所有类别中的第三篇文章,然后将它们全部合并并按类别排序

似乎LIMIT不支持与in结合使用,但一次检索一条记录就可以了

如果你有更好的方法,我仍然对你的解决方案感兴趣


谢谢

这是对您的解决方案的简化

    select *
  from articles a
  where a.article_id =
      (select f.article_id
        from articles f
        where f.category_id = a.category_id
        order by f.is_sticky, f.published_at
        limit 1) or a.article_id =
      (select f.article_id
        from articles f
        where f.category_id = a.category_id
        order by f.is_sticky, f.published_at
        limit 1, 1) or 
    a.article_id =
      (select f.article_id
        from articles f
        where f.category_id = a.category_id
        order by f.is_sticky, f.published_at
        limit 2, 1)

看看这个名为的代码段

根据设置的大小,有两种解决方案可供选择,一种是使用计数,另一种是使用临时表来处理较大的表

因此,基本上,如果您有一个大表,在MySQL实现子查询限制或类似的限制之前,您必须手动(或者在循环中使用动态查询)使用此处建议的解决方案之一聚合所有类别


//使用临时表和存储过程的解决方案:

运行一次:

DELIMITER //
CREATE PROCEDURE top_articles()
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE catid INT;
    DECLARE cur1 CURSOR FOR SELECT DISTINCT(category_id) FROM articles;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
    OPEN cur1;
    # This temporary table will hold all top N article_id for each category
    CREATE TEMPORARY TABLE top_articles (
        article_id int(10) unsigned NOT NULL
    );
    # Loop through each category
    REPEAT
        FETCH cur1 INTO catid;
        INSERT INTO top_articles
        SELECT article_id FROM articles
        WHERE category_id = catid
        ORDER BY is_sticky DESC, published_at
        LIMIT 3;
    UNTIL done END REPEAT;
    # Get all fields in correct order based on our temporary table
    SELECT * FROM articles WHERE article_id 
    IN (SELECT article_id FROM top_articles)
    ORDER BY category_id, is_sticky DESC, published_at;
    # Remove our temporary table
    DROP TEMPORARY TABLE top_articles;
END;
//
DELIMITER ;
然后,尝试一下:

CALL top_articles();
你应该看到你等待的结果。它应该适用于每个类别的任意数量的文章,并且可以轻松地适用于任意数量的类别。这就是我得到的:

+------------+-------------+-------+-----------+---------------------+
| article_id | category_id | title | is_sticky | published_at        |
+------------+-------------+-------+-----------+---------------------+
|          5 |           1 | qox   |         1 | 2009-02-09 00:00:00 | 
|          1 |           1 | foo   |         0 | 2009-02-06 00:00:00 | 
|          2 |           1 | foo   |         0 | 2009-02-06 00:00:00 | 
|          9 |           2 | qox   |         1 | 2009-02-09 00:00:00 | 
|          6 |           2 | foo   |         0 | 2009-02-06 00:00:00 | 
|          7 |           2 | bar   |         0 | 2009-02-07 00:00:00 | 
+------------+-------------+-------+-----------+---------------------+

虽然我不知道这将如何转化为性能方面的问题。它可能会被优化和清理一点。

让我想起了什么时候子查询是不允许进入的MySQL@Brettski,我相信他的意思是在提问中有限制。阅读他的最新问题,也许?我的正确答案是“停止使用MySQL”:)这个查询在PostgreSQL中运行得很好。这是一个非常好的链接。谢谢虽然我不能使用这些解决方案。如果可以的话,我还是会投你的票。我想我们可以投15分,而你似乎有23分。但别担心,我只是好奇我们如何才能做到这一点在这里,您可以尝试专门为您的文章示例调整的临时解决方案。祝你好运