在临时表MySQL中获取行位置

时间:2015-01-14 18:49:31

标签: mysql sql join position row

所以我正在编写一个临时表,根据positiontotal_points顺序设置DESC,IE用户拥有的点越多,排名越高会有。

我还会从此表格中选择一个subscriber_id,以便让给定的用户获得当前position

然而,我遇到了很多奇怪的问题,这是我的代码:

SET @rownum := 0;

SELECT t.`subscriber_id`,
t.`total_points`,
s.`account_type`,
@rownum := @rownum + 1 AS `position`
FROM `subscribers_points` t
LEFT JOIN (
    SELECT `id`, `account_type` 
    FROM `subscribers`
) s
    on s.`id` = t.`subscriber_id`
WHERE t.`year` = 2015
AND t.`month` = 1
ORDER BY t.`total_points` DESC

我想过滤掉1,2和9中的所有account_types,但只要我将其添加到subscribers_points WHERE子句,我的表就不再基于{position total_points 1}},但subscriber_id只是奇怪而且对我没有意义。

为了澄清,表subscribers包含account_type字段。 subscriber_points表包含total_points字段。

理想的表格应该是这样的:

-------------------------------------------------------------
|  subscriber_id |  position |  total_points | account_type  |
-------------------------------------------------------------
|    52          |     1     |       10      |       7       |
|   125          |     2     |       8       |       4       |
|    87          |     3     |       9       |       3       |
|    12          |     4     |       5       |       6       |
|    45          |     5     |       2       |       4       |
-------------------------------------------------------------

提前谢谢

2 个答案:

答案 0 :(得分:2)

MySQL在计算行间值时很不可靠:

具有6个连续值的基本简单表:

mysql> create table foo (x int);
mysql> insert into foo (x) values (0), (1), (2), (3), (4), (5);

mysql> set @pos := 0;
mysql> select @pos := @pos + 1, x from foo where x not in (2, 3);
+------------------+------+
| @pos := @pos + 1 | x    |
+------------------+------+
|                1 |    0 |
|                2 |    1 |
|                3 |    4 |
|                4 |    5 |
+------------------+------+

一切看起来都不错。我们已经消除了两行,位置编号是顺序的,看起来MySQL正确地不评估@pos更新,除非结果集中包含一行。但是你在系统中添加了一些顺序:

mysql> set @pos := 0;
mysql> select @pos := @pos + 1, x from foo where x not in (2, 3) order by x desc;
+------------------+------+
| @pos := @pos + 1 | x    |
+------------------+------+
|                1 |    5 |
|                2 |    4 |
|                3 |    1 |
|                4 |    0 |
+------------------+------+

注意位置是如何递增的,即使我们已经颠倒了行的顺序。您认为在扫描表格并包含/排除行时,将评估@pos + 1内容。但不,不。它以某种方式完成 AFTER 包含和排序行。

这意味着您的计算位置基本上与您在查询的其余部分中检索的值无关。但更令人困惑的是,如果你按照职位排序:

mysql> set @pos := 0;
mysql> select @pos := @pos + 1 as pos, x from foo where x not in (2, 3) order by pos desc;
+------+------+
| pos  | x    |
+------+------+
|    4 |    5 |
|    3 |    4 |
|    2 |    1 |
|    1 |    0 |
+------+------+

x值与位置一起排序。因此,无论将这些位置值与匹配的记录粘合在一起,都是......不可思议。

答案 1 :(得分:0)

好的我找到了解决方案,但它基本上包括创建2个临时表以在同一个地方获取我想要的确切值,然后运行SELECT以获得给用户的正确等级。

以下代码:

    CREATE TEMPORARY TABLE IF NOT EXISTS `temp_rank_table` AS(
        SELECT p.`subscriber_id`, p.`total_points`, s.`account_type`
        FROM `subscribers_points` p 
            LEFT JOIN `subscribers` s
            ON s.`id` = p.`subscriber_id`
        WHERE p.`year` = _year
        AND p.`month` = _month
        AND s.`account_type` BETWEEN 3 AND 8
        AND `password_created` = 1
        AND `verified` = 1
        AND `active` = 1
        ORDER BY p.`total_points` DESC
    );

    SET @rank=0;

    CREATE TEMPORARY TABLE IF NOT EXISTS `temp_rank_table_count` AS(
        SELECT @rank:=@rank+1 AS `rank`, `subscriber_id`, `total_points`
        FROM `temp_rank_table`
        ORDER BY `total_points` DESC
    );

    #

    SELECT t.`rank`, t.`subscriber_id`, t.`total_points`
    FROM `temp_rank_table_count` t
    WHERE `subscriber_id` = _subscriber_id;

    DROP TABLE `temp_rank_table`;
    DROP TABLE `temp_rank_table_count`;