Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 从数百万条记录中选择排名_Mysql_Sql_Innodb - Fatal编程技术网

Mysql 从数百万条记录中选择排名

Mysql 从数百万条记录中选择排名,mysql,sql,innodb,Mysql,Sql,Innodb,我会向SO寻求帮助,因为我找不到类似的情况、问题/帖子 假设我有数百万条记录,列是 用户id-假设其记录范围为1到1000000 名称-假设它还记录了多达20个字母 分数-0到100,假设其也已记录 日期-记录的日期时间戳 假设我知道我的用户id是什么,我想知道我自己的排名 我还想获得排名上下的其他10个用户记录,比如说我的排名是100,我还想选择排名在我排名上90到99,排名下101到110的用户。 若不同的用户按记录的日期具有相同的分数顺序排名,则较早的记录具有较高的排名。 可能吗? 假设所

我会向SO寻求帮助,因为我找不到类似的情况、问题/帖子

假设我有数百万条记录,列是 用户id-假设其记录范围为1到1000000 名称-假设它还记录了多达20个字母 分数-0到100,假设其也已记录 日期-记录的日期时间戳

假设我知道我的用户id是什么,我想知道我自己的排名 我还想获得排名上下的其他10个用户记录,比如说我的排名是100,我还想选择排名在我排名上90到99,排名下101到110的用户。 若不同的用户按记录的日期具有相同的分数顺序排名,则较早的记录具有较高的排名。 可能吗? 假设所有记录都是唯一的,并且没有设置索引

我知道如何排序

SELECT * FROM record order by score
但是这会让我选择所有的记录,在不选择每个记录的情况下选择特定数据的实际方法是什么

以下是我想要实现的目标

user_id |   name   | score |        date          |     rank     |
------------------------------------------------------------------
12341   |   namep  |   90  | 2017-01-01 04:02:36  |      90      |
45341   |   nameo  |   88  | 2017-01-02 00:05:45  |      91      |
24341   |   namex  |   88  | 2017-01-03 00:11:15  |      92      |
26867   |   namec  |   83  | 2017-01-03 01:41:23  |      93      |
19156   |   nameb  |   81  | 2017-01-03 02:36:45  |      94      |
74973   |   namem  |   79  | 2017-01-03 04:07:55  |      95      |
23134   |   namek  |   78  | 2017-01-04 02:01:25  |      96      |
21424   |   namet  |   77  | 2017-01-04 02:41:33  |      97      |
19534   |   nameg  |   77  | 2017-01-04 02:56:15  |      98      |
74912   |   namez  |   75  | 2017-01-04 04:07:55  |      99      |

my_uid  |  my_name |   75  | 2017-01-04 13:07:45  |     100      |

86766   |   namen  |   75  | 2017-01-04 14:21:47  |     101      |
67976   |   namey  |   74  | 2017-01-04 16:22:23  |     102      |
34676   |   nameu  |   74  | 2017-01-04 17:33:32  |     103      |
86236   |   namei  |   73  | 2017-01-04 18:11:09  |     104      |
98636   |   nameo  |   73  | 2017-01-04 19:21:47  |     105      |
14326   |   namep  |   73  | 2017-01-04 20:33:22  |     106      |
45333   |   namet  |   72  | 2017-01-04 20:44:12  |     107      |
33323   |   namer  |   72  | 2017-01-04 21:34:26  |     108      |
11322   |   namee  |   71  | 2017-01-04 22:51:54  |     109      |
86633   |   namew  |   70  | 2017-01-04 22:55:33  |     110      |
好的,这是我现在得到的,很抱歉,我没有提到任何关于不使用union或UNIONALL的内容,我不能在我的项目中使用它

但无论如何,这是我的疑问 我使用了multi_查询函数

$sql = "SELECT score, date FROM table_name WHERE user_id=your_user_id;" //assume you already know your user_id
$sql .= "SELECT name, score, date FROM table_name WHERE score >= your_score ORDER BY score, date LIMIT 10;"; //to get 10 rows that have greater or same score of your score order by date, earlier date is higher rank if score is the same with other user.
$sql .= "SELECT name, score, date table_name WHERE score <= your_score DESC, date ASC LIMIT 10"; //select score less than or equal to my score order by score and date
我的问题是,当使用多个查询时,它仍然与执行3个不同的查询相同,因为我有3个查询,如何将其组合为一个?不使用union或union all?
在第三个查询中,如何从数据设置起点?

在MySQL中,view就像其他语言中的函数一样

CREATE VIEW rankall AS SELECT * FROM record ORDER BY score;

SELECT * FROM rankall
    WHERE rank > (SELECT rank FROM rankall WHERE user_id = ID) - 11
    AND rank < (SELECT rank FROM rankall WHERE user_id = ID) + 11;
这是基本思想,但不能保证上述代码能正常工作:试试这个

SELECT user_id, name, score FROM record
WHERE score BETWEEN 
CONVERT((SELECT score FROM record WHERE user_id = (SELECT user_id FROM record WHERE score = '100') ), INTEGER) - 10
AND
CONVERT((SELECT score FROM record WHERE user_id = (SELECT user_id FROM record WHERE score = '100') ), INTEGER) + 10
ORDER BY score DESC, date DESC

这是一个可行的方法,但也有一些问题需要解决。这将获得所选用户的任意一方得分以及该用户的排名。然后按分数排序并计算排名。这确实正常工作,但如果所选用户是得分最高/最低的用户,则会出现问题。可以对其进行排序,但不确定实际数据是否可用。但我会给你一些想法

这是使用用户id 86474作为您感兴趣的用户id,并且每侧仅获得1-只是为了适合您提供的测试数据:-

SELECT user_id,
        name, 
        score, 
        date,
        def_rank - (@ranking := @ranking -1) AS rank
FROM
(
    SELECT *
    FROM
    (
        (SELECT r1.user_id,
                r1.name, 
                r1.score, 
                r1.date,
                sub0.def_rank
        FROM record r1
        INNER JOIN record r2 ON r2.user_id = 86476
        CROSS JOIN 
        (
            SELECT COUNT(*) def_rank
            FROM record r1
            INNER JOIN record r2 ON r2.user_id = 86476
            WHERE r1.score >= r2.score
        ) sub0
        WHERE r1.score >= r2.score
        ORDER BY score ASC
        LIMIT 2) 
        UNION
        (SELECT r1.user_id,
                r1.name, 
                r1.score, 
                r1.date,
                sub0.def_rank
        FROM record r1
        INNER JOIN record r2 ON r2.user_id = 86476
        CROSS JOIN 
        (
            SELECT COUNT(*) def_rank
            FROM record r1
            INNER JOIN record r2 ON r2.user_id = 86476
            WHERE r1.score >= r2.score
        ) sub0
        WHERE r1.score <= r2.score
        ORDER BY score DESC
        LIMIT 2)
    ) sub97
    ORDER BY score
) sub1
CROSS JOIN 
(
    SELECT @ranking := 2
) sub2

我终于得到了我想要的,所以我只回答我自己的问题

SELECT score, date FROM rank WHERE uid=your_user_id; //your score and date recorded
SELECT (count(*) + 1) AS rank FROM rank WHERE score > your_score OR (score = your_score AND date < date of your score recorded); //your rank
SELECT * FROM rank WHERE score > your_score OR (score = your_score AND date < date of your score recorded) ORDER BY score ASC, date DESC LIMIT 10; //10 users above my rank, in your output you have to reverse the order
SELECT * FROM rank WHERE score < your_score OR (score = your_score AND date > date of your score recorded) ORDER BY score DESC, date ASC LIMIT 10; //10 users below my rank

感谢其他回复的用户:

可能与@Takarii重复感谢您的回复,我将查看此帖子!查看MariaDB中可用的窗口功能。感谢您的回复!我忘了提到我必须使用MySQL,但我会看看窗口功能。@Takarii在我的项目中,我不能使用union或union all,可能吗?当然,上面的代码不起作用。排名本身不会突然出现在你的视野中。谢谢你的回复!对于初学者来说,它看起来非常复杂,我只知道基本知识,但我会看一看,谢谢你的想法!
CREATE VIEW rankall AS SELECT * FROM record ORDER BY score;

SELECT * FROM rankall
    WHERE rank > (SELECT rank FROM rankall WHERE user_id = ID) - 11
    AND rank < (SELECT rank FROM rankall WHERE user_id = ID) + 11;
SELECT user_id, name, score FROM record
WHERE score BETWEEN 
CONVERT((SELECT score FROM record WHERE user_id = (SELECT user_id FROM record WHERE score = '100') ), INTEGER) - 10
AND
CONVERT((SELECT score FROM record WHERE user_id = (SELECT user_id FROM record WHERE score = '100') ), INTEGER) + 10
ORDER BY score DESC, date DESC
SELECT user_id,
        name, 
        score, 
        date,
        def_rank - (@ranking := @ranking -1) AS rank
FROM
(
    SELECT *
    FROM
    (
        (SELECT r1.user_id,
                r1.name, 
                r1.score, 
                r1.date,
                sub0.def_rank
        FROM record r1
        INNER JOIN record r2 ON r2.user_id = 86476
        CROSS JOIN 
        (
            SELECT COUNT(*) def_rank
            FROM record r1
            INNER JOIN record r2 ON r2.user_id = 86476
            WHERE r1.score >= r2.score
        ) sub0
        WHERE r1.score >= r2.score
        ORDER BY score ASC
        LIMIT 2) 
        UNION
        (SELECT r1.user_id,
                r1.name, 
                r1.score, 
                r1.date,
                sub0.def_rank
        FROM record r1
        INNER JOIN record r2 ON r2.user_id = 86476
        CROSS JOIN 
        (
            SELECT COUNT(*) def_rank
            FROM record r1
            INNER JOIN record r2 ON r2.user_id = 86476
            WHERE r1.score >= r2.score
        ) sub0
        WHERE r1.score <= r2.score
        ORDER BY score DESC
        LIMIT 2)
    ) sub97
    ORDER BY score
) sub1
CROSS JOIN 
(
    SELECT @ranking := 2
) sub2
SELECT score, date FROM rank WHERE uid=your_user_id; //your score and date recorded
SELECT (count(*) + 1) AS rank FROM rank WHERE score > your_score OR (score = your_score AND date < date of your score recorded); //your rank
SELECT * FROM rank WHERE score > your_score OR (score = your_score AND date < date of your score recorded) ORDER BY score ASC, date DESC LIMIT 10; //10 users above my rank, in your output you have to reverse the order
SELECT * FROM rank WHERE score < your_score OR (score = your_score AND date > date of your score recorded) ORDER BY score DESC, date ASC LIMIT 10; //10 users below my rank