繁体   English   中英

从表中获取 3 个最高值

[英]Get 3 highest values from table

我想计算具有最多归因行的前 3 个用户。

SQL表:

ID | IdUser |  Type   |
-----------------------
0  |    1   |  like   |
1  |    1   |  like   |
2  |    4   | dislike |
3  |    5   | dislike |
4  |    1   |  like   |
5  |    4   |  like   |
6  |    5   |  like   |
8  |    4   |  like   |
9  |    4   |  like   |
10 |    3   |  like   |
11 |    5   |  like   |
12 |    9   |  like   |

结果应该是:

idUser[1] with 3 times "like" and 0 "dislike" (3-0 = 3 points)
idUser[4] with 3 times "like" and 1 "dislike" (3-1 = 2 points)
idUser[5] with 2 times "like" and 1 "dislikes (2-1 = 1 point )

所以我想要做的是获得 idUser 1(3 分),然后是 idUser4(2 分),最后是 idUser 5(1 分)和他们的分数。

我尝试了不同的方法,但都没有奏效。

在这里,我尝试使用所有数据创建一个二维数组,然后获取最高值,但我无法执行第二部分。

表“users”记录了网站的所有用户表“points”记录了喜欢和不喜欢

$sqlUsers = "SELECT * FROM users";
$resultUsers = $conn->query($sqlUsers);

$recordsArray = array(); //create array

while($rowUsers = $resultUsers->fetch_assoc()) {

    $idUser = $rowUsers['id'];

    //COUNT LIKES OF THE USER
    $sqlLikes = "SELECT COUNT(id) AS numberLikes FROM points WHERE idCibledUser='$idUser' AND type='like'";
    $resultLikes = $conn->query($sqlLikes);
    $rowLikes = $resultLikes->fetch_assoc();

    //COUNT DISLIKES OF THE USER
    $sqlDislikes = "SELECT COUNT(id) AS numberDislikes FROM points WHERE idCibledUser='$idUser' AND type='dislike'";
    $resultDislikes = $conn->query($sqlDislikes);
    $rowDislikes = $resultDislikes->fetch_assoc();

    //GET POINTS BY SUBTRACTING DISLIKES FROM LIKES
    $points = $rowLikes['numberLikes'] - $rowDislikes['numberDislikes'];

    $recordsArray[] = array($idUser => $points);

}

如果您最终只需要总分而没有喜欢和不喜欢的细分(从您的问题中并不完全清楚):

SELECT IdUser, SUM(IF(Type='like',1,-1)) AS points
FROM users
GROUP BY IdUser
ORDER BY points DESC
LIMIT 3

如果你想要完整的细分:

SELECT IdUser,
       SUM(IF(Type='like',1,-1)) AS points,
       SUM(IF(Type='like',1,0)) as likes,
       SUM(IF(Type='dislike',1,0)) as dislikes
FROM users
GROUP BY IdUser
ORDER BY points DESC
LIMIT 3

解释

假设我想计算Type列值为'like'的总行数。 我可以执行以下操作:

SELECT COUNT(*) AS cnt FROM users WHERE Type = 'like'

但另一种可能不太直接的方法是:

SELECT SUM(IF(Type = 'like', 1, 0)) AS cnt FROM users

在上面的 SQL 中,正在检查每行中的Type列,如果等于'like' ,则将 1 的值分配给该列,否则为 0。然后使用SUM函数将所有这些 1 和 0 相加。 通过将所有 1 相加,您实际上是在计算Type列中具有'like'的行数。 第二种方法允许您一次处理喜欢和不喜欢的数量:

SELECT SUM(IF(Type = 'like', 1, 0)) AS likes,
       SUM(IF(Type = 'dislike', 1, 0)) AS dislikes
       FROM users

但是,如果您想逐个用户地获得上述计数怎么办? 这就是GROUP BY子句的目的:

SELECT IdUser,
       SUM(IF(Type = 'like', 1, 0)) AS likes,
       SUM(IF(Type = 'dislike', 1, 0)) AS dislikes
       FROM users
       GROUP BY IdUser

如果我们将值 1 分配给包含'like'的列,如果包含'dislike' (或不是'like'则将值分配给 -1,则可以计算“分数”或喜欢和不喜欢之间的差异),然后将这些值相加:

SELECT IdUser,
       SUM(IF(Type = 'like', 1, -1)) AS points,
       SUM(IF(Type = 'like', 1, 0)) as likes,
       SUM(IF(Type = 'dislike', 1, 0)) as dislikes
FROM users
GROUP BY IdUser

最后,如果您想要三个最高分,请按降序对返回的行进行排序( ORDER BY points DESC )并仅保留返回的前 3 行( LIMIT 3 ):

SELECT IdUser,
       SUM(IF(Type = 'like', 1, -1)) AS points,
       SUM(IF(Type = 'like', 1, 0)) as likes,
       SUM(IF(Type = 'dislike', 1, 0)) as dislikes
FROM users
GROUP BY IdUser
ORDER BY points DESC
LIMIT 3

如果您需要经常获得喜欢/不喜欢,请参阅下面的解决方案, points表经常更新并且数据相关性很重要,即您不想缓存结果。

创建另一个表,如user_points_summary ,它将有 2 列,例如IdUserPoints IdUser要在此表中是唯一的,必须在将新行添加到points表时触发Points重新计算(每个用户)。

如果您需要喜欢/不喜欢细分,那么此表将有 3 列 - IdUser (不再是唯一的)、 likes_countdislikes_count 然后相同 - 在points表中插入/更新/删除行时触发此表更新。

如果您选择第二个选项(按喜欢/不喜欢细分) - 这是创建表语句的示例:

CREATE TABLE `user_points_summary` (
  `IdUser` int(11) NOT NULL,
  `likes_count` int(11) NOT NULL DEFAULT '0',
  `dislikes_count` int(11) NOT NULL DEFAULT '0',
  KEY `idx_user_points_summary_IdUser` (`IdUser`)
) ENGINE=InnoDB;

然后您可以将以下触发器添加到您的users表中,这将在添加新用户时添加零个喜欢/不喜欢:

CREATE TRIGGER `users_AFTER_INSERT` AFTER INSERT ON `users` FOR EACH ROW
BEGIN
    INSERT INTO `user_points_summary` VALUE (NEW.`IdUser`, 0, 0);
END

然后将以下触发器添加到points表中以更新user_points_summary喜欢/不喜欢计数:

DELIMITER $$
CREATE TRIGGER `points_AFTER_INSERT` AFTER INSERT ON `points` FOR EACH ROW
BEGIN
    IF NEW.`Type` = 'like' THEN
        UPDATE `user_points_summary` SET `likes_count` = `likes_count` + 1 WHERE `IdUser` = NEW.`IdUser`;
    ELSEIF NEW.`Type` = 'dislike' THEN
        UPDATE `user_points_summary` SET `dislikes_count` = `dislikes_count` + 1 WHERE `IdUser` = NEW.`IdUser`;
    END IF;
END $$

CREATE TRIGGER `points_AFTER_UPDATE` AFTER UPDATE ON `points` FOR EACH ROW
BEGIN
    IF NEW.`Type` = 'dislike' AND OLD.`Type` = 'like' THEN
        UPDATE `user_points_summary`
            SET 
                `likes_count` = `likes_count` - 1,
                `dislikes_count` = `dislikes_count` + 1
        WHERE `IdUser` = `OLD`.`IdUser`;
    ELSEIF NEW.`Type` = 'like' AND OLD.`Type` = 'dislike' THEN
        UPDATE `user_points_summary`
            SET 
                `dislikes_count` = `dislikes_count` - 1,
                `likes_count` = `likes_count` + 1
        WHERE `IdUser` = OLD.`IdUser`;
    END IF;
END $$

CREATE TRIGGER `points_AFTER_DELETE` AFTER DELETE ON `points` FOR EACH ROW
BEGIN
    IF OLD.`Type` = 'like' THEN
        UPDATE `user_points_summary`
            SET `likes_count` = `likes_count` - 1
        WHERE `IdUser` = `OLD`.`IdUser`;
    ELSEIF OLD.`Type` = 'dislike' THEN
        UPDATE `user_points_summary`
            SET `dislikes_count` = `dislikes_count` - 1
        WHERE `IdUser` = OLD.`IdUser`;
    END IF;
END $$
DELIMITER ;

然后您可以使用以下查询来获取用户点数的喜欢和不喜欢计数:

SELECT *, `likes_count` - `dislikes_count` AS `points` 
FROM `user_points_summary`
ORDER BY `points` DESC
LIMIT 3

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM