重写MySQL查询
我将试着在另一个问题上更好地解释这一点。这是我认为应该可以使用的查询,但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
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分。但别担心,我只是好奇我们如何才能做到这一点在这里,您可以尝试专门为您的文章示例调整的临时解决方案。祝你好运