Решение для ранжирования SQL - PullRequest
1 голос
/ 25 июня 2009

Я внедряю решение ранжирования для одной из моих таблиц, чтобы оптимизировать запросы на чтение, чтобы избавиться от дорогих запросов, в которых используются предложения COUNT (*), LIMIT и OFFSET. Моя проблема в том, что я не знаю, почему расчет позиции неверен. Пожалуйста, посмотрите на мой пример, чтобы воспроизвести проблему.

CREATE TABLE `acl`
(
    `id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(32) NOT NULL,
    `limiter` INTEGER(11) SIGNED NULL,
    PRIMARY KEY (`id`)
)
ENGINE=INNODB;

CREATE TABLE `quote`
(
    `id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT,
    `created_at` INTEGER(11) UNSIGNED NOT NULL,
    `reputation` INTEGER(11) SIGNED NOT NULL,
    PRIMARY KEY (`id`)
)
ENGINE=INNODB;

INSERT INTO `acl` (`name`, `limiter`) VALUES ('Users', 0), ('Staff', null);
INSERT INTO `quote` (`created_at`, `reputation`) 
  VALUES (UNIX_TIMESTAMP(), 0), (UNIX_TIMESTAMP()+1, 0);

SET @acl_id := 0, @position := 0;
SELECT acl.id AS acl_id, quote.id AS quote_id, 
  GREATEST(@position := IF(@acl_id = acl.id, @position + 1, 1), 
    LEAST(0, @acl_id := acl.id)) AS position 
FROM acl JOIN quote 
  ON (acl.limiter IS NULL OR quote.reputation >= acl.limiter) 
ORDER BY acl.id ASC, quote.created_at DESC;

Мне бы хотелось, чтобы запрос select выбрал все строки acl и одновременно соединил их со строками кавычек, установил их позицию, но все, что я получил, это position = 1 для каждой строки. Кто-то предложил мне перенести присваивание переменных в предложение JOIN или ORDER, но проблема остается. У меня вопрос ... как назначить позицию в одном запросе?

Ответы [ 2 ]

0 голосов
/ 25 июня 2009

Слегка измененный запрос из статьи в моем блоге:

SELECT  q.*,
        @r := @r + 1
FROM    (
        SELECT  @_acl_id := -1,
                @r := 0
        ) vars
STRAIGHT_JOIN
        (
        SELECT  acl.id AS acl_id, quote.id AS quote_id
        FROM    acl
        JOIN    quote
        ON      (acl.limiter IS NULL OR quote.reputation >= acl.limiter)
        ORDER BY
                acl.id ASC, quote.created_at DESC
        ) q
WHERE   CASE WHEN @_acl_id <> acl_id THEN @r := 0 ELSE 0 END IS NOT NULL
        AND (@_acl_id := acl_id) IS NOT NULL
0 голосов
/ 25 июня 2009

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

(В некоторых случаях вы можете вызывать специальные эффекты с пользовательскими переменными, но вам нужно использовать эту технику с большой осторожностью. Ошибиться легко, потому что вам нужно понять порядок вычисления строк, который может не будет порядок, указанный в предложении ORDER BY.)

Спасибо за включение полного SQL, который показывает структуру вашей таблицы и примеры данных. Вы показали SQL-запрос, который не выполняет то, что вы хотите, и вы говорите, что хотите какое-то решение по ранжированию, но ранжирование по каким критериям? В каком порядке вы хотите, чтобы строки были, и какое подмножество строк вы хотите? Вы должны четко понимать свою цель, когда задаете такие вопросы.

Пожалуйста, отредактируйте ваш вопрос выше и добавьте дополнительную информацию. Пример желаемого выхода будет лучшим. Если ты сможешь это сделать, я проверю и попробую помочь.

PS: я знаю, что вы не можете оставлять комментарии, пока не наберете 50 очков репутации. Попробуйте отредактировать исходный вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...