我正在为我的一张表实施排名解决方案,以优化读取查询以摆脱使用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;
我希望选择查询来提取所有acl行,并同时将它们与报价行连接起来,设置它们的位置,但是我得到的只是每一行的position = 1。有人建议我将变量分配移至JOIN或ORDER子句,但问题仍然存在。我的问题是...如何在单个查询中分配位置?
最佳答案
我的博客文章中的查询略作修改:
Analytic functions: SUM
, AVG
, ROW_NUMBER
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