按添加时间排序结果,但按票数排名
Order results by time added, but rank them by vote count
我正在编写一个网络应用程序,人们可以在其中添加想法并对其进行投票。在输出想法时,我希望它们按总票数或添加时间排序,但始终有一个基于票数的排名。
这是我现在拥有的:
function get_ideas($status, $sortby, $count, $page){
$offset = ($page - 1) * $count;
$dbh = db_connect();
if($sortby === 'popular'){
$stmt = $dbh->prepare("
SELECT i.idea_id, i.idea_datetime, i.user_id, i.idea_title, i.idea_text,
i.idea_vote_count, u.user_name, @curRank := @curRank + 1 AS rank
FROM ideas i
JOIN (SELECT @curRank := :rankoffset) AS q
JOIN users u ON i.user_id = u.user_id
WHERE idea_status = :idea_status
ORDER BY idea_vote_count DESC
LIMIT :count
OFFSET :offset;");
} else {
$stmt = $dbh->prepare("HOW DO I DO THIS???");
}
$stmt->bindParam(':idea_status', $status, PDO::PARAM_STR);
$stmt->bindParam(':rankoffset', $offset, PDO::PARAM_INT);
$stmt->bindParam(':count', $count, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = NULL;
$dbh = NULL;
return $result;
}
"if" 块中的代码按预期工作 - 它 returns 一个按 "idea_vote_count" 排序并具有正确等级的数组。
但是,我不知道第二个陈述应该是什么。只需将 "ORDER BY" 子句中的 "idea_vote_count" 更改为 "idea_id" 即可轻松实现按时间添加的排序。但是,我如何获得排名?我想不出也找不到不涉及将排名存储在 table 本身中的解决方案。
希望我已经清楚地解释了我的问题,但以防万一:
如何获得这样的 table:
idea_id | idea_vote_count
1 | 20
2 | 40
3 | 30
4 | 5
要产生这样的输出:
rank | idea_id | idea_vote_count
4 | 4 | 5
2 | 3 | 30
1 | 2 | 40
3 | 1 | 20
此外,我对 PHP 和 MySQL 有点陌生,所以如果您发现任何其他问题,请指出。
期待您的建议。谢谢:)
编辑:对于草莓:
我的想法table:
CREATE TABLE `ideas`(
`idea_id` int NOT NULL AUTO_INCREMENT,
`idea_datetime` datetime NOT NULL,
`user_id` int NOT NULL,
`idea_title` varchar(48) NOT NULL,
`idea_text` text NOT NULL,
`idea_vote_count` int NOT NULL DEFAULT 0,
`idea_status` varchar(16) NOT NULL DEFAULT 'active',
PRIMARY KEY(`idea_id`),
FOREIGN KEY(`user_id`) REFERENCES users(`user_id`))
ENGINE=INNODB;
示例想法是通过以下脚本生成的。然后我手动将第 100 行的 idea_vote_count
更改为第 5 行。
$i = 1;
set_time_limit(150);
while (i<101) {
$datetime = date('Y-m-d h:m:s');
$dbh->exec(INSERT INTO `ideas` (`idea_datetime`, `user_id`, `idea_title`, `idea_text`, `idea_vote_count`, `idea_status`)
VALUES ('{$datetime}', $i, 'Title{$i}', 'Text{$i}', $i, 'active');
$i++
sleep(1);
}
这是我将 Strawberry 的 SQL 合并到我的函数中后的结果:
function get_ideas($status, $sortby, $count, $page){
$offset = ($page - 1) * $count;
$dbh = db_connect();
if($sortby === 'popular'){
$stmt = $dbh->prepare("
SELECT i.idea_id, i.idea_datetime, i.user_id, i.idea_title, i.idea_text, i.idea_vote_count, u.user_name, @curRank := @curRank + 1 AS rank
FROM ideas i
JOIN (SELECT @curRank := :rankoffset) AS q
JOIN users u
ON i.user_id = u.user_id
WHERE idea_status = :idea_status
ORDER BY idea_vote_count DESC
LIMIT :count
OFFSET :offset;");
} else {
$stmt = $dbh->prepare("
SELECT n.*
FROM (
SELECT i.idea_id, i.idea_datetime, i.user_id, i.idea_title, i.idea_text, i.idea_vote_count, u.user_name, @curRank := @curRank + 1 AS rank
FROM ideas i
JOIN (SELECT @curRank := :rankoffset) AS q
JOIN users u
ON i.user_id = u.user_id
WHERE idea_status = :idea_status
ORDER BY idea_vote_count DESC
LIMIT :count
OFFSET :offset) n
ORDER BY idea_id DESC;");
}
$stmt->bindParam(':idea_status', $status, PDO::PARAM_STR);
$stmt->bindParam(':rankoffset', $offset, PDO::PARAM_INT);
$stmt->bindParam(':count', $count, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = NULL;
$dbh = NULL;
return $result;
}
如您所见,该函数将 $count 和 $page 作为参数(通常它们的值为 $_REQUEST['count/page'])并根据它们计算偏移量和限制。这一点很重要,因为我不想同时向用户展示所有的想法,我想把它们分成几个页面。但是,这会以下列方式与 select/ranking SQL 混淆:
当 $page = 1 和 $count = 100 时,您得到 LIMIT 100 OFFSET 0 并且脚本按预期工作 - 它显示最近的行(第 100 行)作为排名第 96 的第一行(仅第 1、2 行, 3, 4 得票数较低), 紧随其后的是排名 1, 2, 3 等的其他最近行。
但是,当 $page = 1 和 $count = 10 时,您会得到 LIMIT 10 OFFSET 0 并且脚本首先输出第 99 行,因为它是评分最高的,但不是最新的。当 $page = 10 时,第 100 行成为结果集中的第一个结果(评分最低和最旧的行,尽管第 100 行是最新的)。
技术上我可以 select 整个 table,然后在 PHP 中处理分页,但我担心性能会受到什么影响。
EDIT2:我已将 OFFSET 和 LIMIT 移动到外部 SELECT,现在一切正常。这样做的副作用是,内部 SELECT select 是整个 table,但希望它不会变得太大以至于服务器无法处理。这是我暂时坚持的解决方案。它基于 Strawberry 的 SQL,因此我将其标记为答案。谢谢,草莓 :)
这是一个想法,纯粹使用 MySQL,但最好只 return 具有等级的数据集,然后在应用程序代码中进行任何进一步排序...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(idea_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,idea_vote_count INT NOT NULL
);
INSERT INTO my_table VALUES
(1 ,20),
(2 ,40),
(3 ,30),
(4 ,5);
SELECT n.*
FROM
( SELECT x.*
, @i:=@i+1 rank
FROM my_table x
, (SELECT @i:=0) vars
ORDER
BY idea_vote_count DESC
) n
ORDER
BY idea_id DESC;
+---------+-----------------+------+
| idea_id | idea_vote_count | rank |
+---------+-----------------+------+
| 4 | 5 | 4 |
| 3 | 30 | 2 |
| 2 | 40 | 1 |
| 1 | 20 | 3 |
+---------+-----------------+------+
我正在编写一个网络应用程序,人们可以在其中添加想法并对其进行投票。在输出想法时,我希望它们按总票数或添加时间排序,但始终有一个基于票数的排名。
这是我现在拥有的:
function get_ideas($status, $sortby, $count, $page){
$offset = ($page - 1) * $count;
$dbh = db_connect();
if($sortby === 'popular'){
$stmt = $dbh->prepare("
SELECT i.idea_id, i.idea_datetime, i.user_id, i.idea_title, i.idea_text,
i.idea_vote_count, u.user_name, @curRank := @curRank + 1 AS rank
FROM ideas i
JOIN (SELECT @curRank := :rankoffset) AS q
JOIN users u ON i.user_id = u.user_id
WHERE idea_status = :idea_status
ORDER BY idea_vote_count DESC
LIMIT :count
OFFSET :offset;");
} else {
$stmt = $dbh->prepare("HOW DO I DO THIS???");
}
$stmt->bindParam(':idea_status', $status, PDO::PARAM_STR);
$stmt->bindParam(':rankoffset', $offset, PDO::PARAM_INT);
$stmt->bindParam(':count', $count, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = NULL;
$dbh = NULL;
return $result;
}
"if" 块中的代码按预期工作 - 它 returns 一个按 "idea_vote_count" 排序并具有正确等级的数组。
但是,我不知道第二个陈述应该是什么。只需将 "ORDER BY" 子句中的 "idea_vote_count" 更改为 "idea_id" 即可轻松实现按时间添加的排序。但是,我如何获得排名?我想不出也找不到不涉及将排名存储在 table 本身中的解决方案。
希望我已经清楚地解释了我的问题,但以防万一:
如何获得这样的 table:
idea_id | idea_vote_count
1 | 20
2 | 40
3 | 30
4 | 5
要产生这样的输出:
rank | idea_id | idea_vote_count
4 | 4 | 5
2 | 3 | 30
1 | 2 | 40
3 | 1 | 20
此外,我对 PHP 和 MySQL 有点陌生,所以如果您发现任何其他问题,请指出。
期待您的建议。谢谢:)
编辑:对于草莓:
我的想法table:
CREATE TABLE `ideas`(
`idea_id` int NOT NULL AUTO_INCREMENT,
`idea_datetime` datetime NOT NULL,
`user_id` int NOT NULL,
`idea_title` varchar(48) NOT NULL,
`idea_text` text NOT NULL,
`idea_vote_count` int NOT NULL DEFAULT 0,
`idea_status` varchar(16) NOT NULL DEFAULT 'active',
PRIMARY KEY(`idea_id`),
FOREIGN KEY(`user_id`) REFERENCES users(`user_id`))
ENGINE=INNODB;
示例想法是通过以下脚本生成的。然后我手动将第 100 行的 idea_vote_count
更改为第 5 行。
$i = 1;
set_time_limit(150);
while (i<101) {
$datetime = date('Y-m-d h:m:s');
$dbh->exec(INSERT INTO `ideas` (`idea_datetime`, `user_id`, `idea_title`, `idea_text`, `idea_vote_count`, `idea_status`)
VALUES ('{$datetime}', $i, 'Title{$i}', 'Text{$i}', $i, 'active');
$i++
sleep(1);
}
这是我将 Strawberry 的 SQL 合并到我的函数中后的结果:
function get_ideas($status, $sortby, $count, $page){
$offset = ($page - 1) * $count;
$dbh = db_connect();
if($sortby === 'popular'){
$stmt = $dbh->prepare("
SELECT i.idea_id, i.idea_datetime, i.user_id, i.idea_title, i.idea_text, i.idea_vote_count, u.user_name, @curRank := @curRank + 1 AS rank
FROM ideas i
JOIN (SELECT @curRank := :rankoffset) AS q
JOIN users u
ON i.user_id = u.user_id
WHERE idea_status = :idea_status
ORDER BY idea_vote_count DESC
LIMIT :count
OFFSET :offset;");
} else {
$stmt = $dbh->prepare("
SELECT n.*
FROM (
SELECT i.idea_id, i.idea_datetime, i.user_id, i.idea_title, i.idea_text, i.idea_vote_count, u.user_name, @curRank := @curRank + 1 AS rank
FROM ideas i
JOIN (SELECT @curRank := :rankoffset) AS q
JOIN users u
ON i.user_id = u.user_id
WHERE idea_status = :idea_status
ORDER BY idea_vote_count DESC
LIMIT :count
OFFSET :offset) n
ORDER BY idea_id DESC;");
}
$stmt->bindParam(':idea_status', $status, PDO::PARAM_STR);
$stmt->bindParam(':rankoffset', $offset, PDO::PARAM_INT);
$stmt->bindParam(':count', $count, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = NULL;
$dbh = NULL;
return $result;
}
如您所见,该函数将 $count 和 $page 作为参数(通常它们的值为 $_REQUEST['count/page'])并根据它们计算偏移量和限制。这一点很重要,因为我不想同时向用户展示所有的想法,我想把它们分成几个页面。但是,这会以下列方式与 select/ranking SQL 混淆:
当 $page = 1 和 $count = 100 时,您得到 LIMIT 100 OFFSET 0 并且脚本按预期工作 - 它显示最近的行(第 100 行)作为排名第 96 的第一行(仅第 1、2 行, 3, 4 得票数较低), 紧随其后的是排名 1, 2, 3 等的其他最近行。
但是,当 $page = 1 和 $count = 10 时,您会得到 LIMIT 10 OFFSET 0 并且脚本首先输出第 99 行,因为它是评分最高的,但不是最新的。当 $page = 10 时,第 100 行成为结果集中的第一个结果(评分最低和最旧的行,尽管第 100 行是最新的)。
技术上我可以 select 整个 table,然后在 PHP 中处理分页,但我担心性能会受到什么影响。
EDIT2:我已将 OFFSET 和 LIMIT 移动到外部 SELECT,现在一切正常。这样做的副作用是,内部 SELECT select 是整个 table,但希望它不会变得太大以至于服务器无法处理。这是我暂时坚持的解决方案。它基于 Strawberry 的 SQL,因此我将其标记为答案。谢谢,草莓 :)
这是一个想法,纯粹使用 MySQL,但最好只 return 具有等级的数据集,然后在应用程序代码中进行任何进一步排序...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(idea_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,idea_vote_count INT NOT NULL
);
INSERT INTO my_table VALUES
(1 ,20),
(2 ,40),
(3 ,30),
(4 ,5);
SELECT n.*
FROM
( SELECT x.*
, @i:=@i+1 rank
FROM my_table x
, (SELECT @i:=0) vars
ORDER
BY idea_vote_count DESC
) n
ORDER
BY idea_id DESC;
+---------+-----------------+------+
| idea_id | idea_vote_count | rank |
+---------+-----------------+------+
| 4 | 5 | 4 |
| 3 | 30 | 2 |
| 2 | 40 | 1 |
| 1 | 20 | 3 |
+---------+-----------------+------+