문제

나는 이것을 다른 질문에 대해 더 잘 설명하려고 노력할 것이다. 이것은 제가 작동해야한다고 생각하는 쿼리이지만 물론 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과 함께 제한이 지원되지는 않지만 한 번에 한 레코드를 검색하는 데 잘 작동합니다.

더 나은 방법이 있다면 여전히 솔루션에 관심이 있습니다.

감사

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top