MySQL запрос к динамическому «Ранжирование строк» - PullRequest
2 голосов
/ 20 октября 2011

У меня проблемы с запуском ранжирования запросов.Внутренний SELECT дает строки в порядке ранжирования, для каждой строки увеличивается переменная @rank, если не позиция, равная предыдущему ранжированию.Но @rank не совсем правильная позиция.

Я пытаюсь сделать ранжирование, сгруппированное и упорядоченное по тем, кто имеет наибольшее значение.

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');

Ответы [ 2 ]

3 голосов
/ 20 октября 2011

имеет
Это будет медленно, но предложение having будет выполнено после того, как все операции выбора, объединения, где и группировки по завершены и полностью разрешены. Единственная проблема в том, что having не использует индекс, в то время как where использует индекс.

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
2 голосов
/ 22 октября 2011

Во-первых, спасибо всем!

Я нашел способ вернуть ожидаемый результат, сделав другой выбор 2

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 |
+------+--------+------+
...