문제
나는 이것을 다른 질문에 대해 더 잘 설명하려고 노력할 것이다. 이것은 제가 작동해야한다고 생각하는 쿼리이지만 물론 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 */
내가 아카이브를하려는 것은 이것입니다 : 기사 테이블에는 여러 카테고리에 대한 몇 가지 기사가 있습니다. 카테고리 당 최대 3 개의 기사 (모든 카테고리)를 얻어야합니다.
데이터는 다음과 같습니다.
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) 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)
다른 팁
이 코드 스 니펫을 살펴보십시오 그룹 내 할당량 (그룹 당 N).
세트의 크기에 따라 두 가지 솔루션이 제안되어 있습니다. 하나는 카운트를 가지고 연주하고 다른 하나는 더 큰 테이블의 임시 테이블을 사용합니다.
따라서 기본적으로 큰 테이블이있는 경우 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 |
+------------+-------------+-------+-----------+---------------------+
비록 그것이 어떻게 성능 면적으로 번역 될지 모르겠지만. 아마도 최적화되고 약간 청소할 수 있습니다.
나는 아마도 게시조차해서는 안되지만 ...
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
카테고리 당 3 개의 기사 만 필요했기 때문에 모든 카테고리의 첫 번째 기사에 대해 쿼리를 세 번 반복 할 수 있습니다 (각 카테고리에 대해 하나의 기사, 두 번째 기사에 대해, 하나는 모든 카테고리의 세 번째 기사 및 가입. 그것들은 모두 카테고리별로 주문합니다.
IN과 함께 제한이 지원되지는 않지만 한 번에 한 레코드를 검색하는 데 잘 작동합니다.
더 나은 방법이 있다면 여전히 솔루션에 관심이 있습니다.
감사