2011-10-20 3 views
1

쿼리 순위를 실행하는 데 문제가 있습니다. 내부 SELECT는 각 행에 대해 순위 순서대로 행을 제공하며, 이전 순위와 같은 위치가 아니라면 @rank 변수가 증가합니다. 그러나 @rank은 실제로 정확한 위치가 아닙니다.MySQL 쿼리에서 동적 "Ranking rows"

나는 가장 높은 가치를 지닌 사람들이 순위를 매기려고 노력하고 있습니다.

SET @prev := NULL; 
SET @curr := NULL; 
SET @rank := 0; 
SELECT 
    @prev := @curr, 
    @curr := SUM(a.value) AS SUM_VALUES, 
    @rank := IF(@prev = @curr, @rank, @rank+1) AS rank, 
    b.id AS b_id, 
    b.name AS b_nome 

FROM 
    a INNER JOIN b ON (a.b_id = b.id) 

GROUP BY b.id 
ORDER BY SUM_VALUES DESC; 

결과 :

여기
---------------------------------------------------- 
@prev := @curr | SUM_VALUES | rank | b_id | b_nome 
---------------|------------|------|-------|-------- 
NULL   | 10   | 2 | 2  | BBB 
NULL   | 2   | 1 | 1  | AAA 

하는 BBB 두번째 순위에서 순위 및 AAA에 처음에 복귀하는 것이다. 그러나 이런 일은 일어나지 않고 있습니다.


갖는 시험 덤프

CREATE TABLE `a` (
    `id` INT(10) NOT NULL AUTO_INCREMENT, 
    `b_id` INT(10) NULL DEFAULT NULL, 
    `value` INT(10) NULL DEFAULT NULL, 
    `name` VARCHAR(50) NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    INDEX `b_id` (`b_id`), 
    CONSTRAINT `fk_b` FOREIGN KEY (`b_id`) REFERENCES `b` (`id`) 
) 
ENGINE=InnoDB; 

CREATE TABLE `b` (
    `id` INT(10) NOT NULL AUTO_INCREMENT, 
    `name` VARCHAR(50) NULL DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) 
ENGINE=InnoDB; 

INSERT INTO `b` (`id`, `name`) VALUES (1, 'AAA'); 
INSERT INTO `b` (`id`, `name`) VALUES (2, 'BBB'); 

INSERT INTO `a` (`id`, `b_id`, `value`, `name`) VALUES (1, 1, 2, 'smaller'); 
INSERT INTO `a` (`id`, `b_id`, `value`, `name`) VALUES (2, 2, 10, 'bigger'); 
+0

당신이 * * 원하는 결과가 무엇입니까? 그건 분명하지 않습니다. 또한 질문에 관계없는 테이블, 열 및 필터를 사용하지 않고도 문제를 보여주는 간단한 데이터 세트로 예제를 단순화하는 데 도움이 될 수 있습니다. 이 질문에서 처리하기에는 너무 많은 부분이 있습니다. 아마 당신이 어떤 반응을 얻지 못했을 것입니다. – mellamokb

+0

좋아, 단순화하려고 시도했습니다. –

답변

3


그것은 느려질 수 있지만 having 절, 어디서 그룹에 의해이 완료 조인, 결국 선택을 실행하고있는 것입니다 완전히 해결되었습니다.
where은 인덱스를 사용하지만 having은 인덱스를 사용하지 않는 유일한 문제입니다.

SELECT 
    ranking stuff 
FROM 
    lot of tables 
WHERE simple_condition 
HAVING filters_that_run_last 

당신은 당신이 명시 적 및 암시 조인 혼합 필요가 없습니다 명시 적
주를 조인합니다.
을 교차 결합하려는 경우 cross join 키워드를 사용할 수 있습니다.

.... 
    ) AS Ranking 
    CROSS JOIN (SELECT @curr := null, @prev := null, @rank := 0) InitVars 
WHERE 
    Ranking.regional_id = 1003 
+0

감사합니다. 기대했던 결과를 가져다 주었던 것처럼 보아라. = P ... 다시, 고맙다. –

+0

당신은 복철이다! –

1

먼저 감사합니다.

나는 다른 선택이

A) 선택 먼저 그룹화

SELECT 
    SUM(a.value) AS SUM_VALUES, 
    b.id AS b_id, 
    b.name AS b_name 
FROM 
    a INNER JOIN b ON (a.b_id = b.id) 
GROUP BY b.id 
ORDER BY SUM_VALUES DESC 

B) 내가이 순위 명부를 주문을 예상 한 결과를 반환하는 방법을 발견

SELECT 
    R.*, 
    @prev := @curr, 
    @curr := R.SUM_VALUES, 
    @rank := IF(@prev = @curr, @rank, @rank+1) AS rank 
FROM (
     SELECT 
      SUM(a.value) AS SUM_VALUES, 
      b.id AS b_id, 
      b.name AS b_name 
     FROM 
      a INNER JOIN b ON (a.b_id = b.id) 
     GROUP BY b.id 
     ORDER BY SUM_VALUES DESC 
) AS R 

c) 그리고 마지막으로, 단지

SELECT 
    Ranking.b_id, 
    Ranking.b_name, 
    Ranking.rank 
FROM 
(
    SELECT 
     R.*, 
     @prev := @curr, 
     @curr := R.SUM_VALUES, 
     @rank := IF(@prev = @curr, @rank, @rank+1) AS rank 
    FROM (
      SELECT 
       SUM(a.value) AS SUM_VALUES, 
       b.id AS b_id, 
       b.name AS b_name 
      FROM 
       a INNER JOIN b ON (a.b_id = b.id) 
      GROUP BY b.id 
      ORDER BY SUM_VALUES DESC 
    ) AS R 
) AS Ranking 
WHERE 
    Ranking.b_id = 1 

이 쿼리의 결과를 중요한 무엇을 선택했다 :

+------+--------+------+ 
| b_id | b_name | rank | 
+------+--------+------+ 
| 1 | AAA | 2 | 
+------+--------+------+