在有限数量的数据中创建具有排名列的视图

时间:2013-04-08 04:56:34

标签: mysql

所以我有一个像这样结构的MySQL表:

CREATE TABLE `spenttime` {
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `userid` int(11) NOT NULL,
    `serverid` int(11) NOT NULL,
    `time` int(11) NOT NULL,
    `day` int(11) NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `dbid_sid_day` (`userid`,`serverid`,`day`)
}

我每天为每个注册玩家存储花在游戏服务器上的时间。 time是花费的时间(以秒为单位),day是每天的unix时间戳(当天开始)。我想在我的数据库上创建一个View,它将显示每个用户每周在服务器上花费的时间,但是显示该时间的列,每周独立于每个服务器。例如数据(为了澄清,我将在此示例中使用日期格式Y-M-D而不是day列的unix时间戳):

INSERT INTO `spenttime` (`userid`, `serverid`, `time`, `day`) VALUES
    (1, 1, 200, '2013-04-01'),
    (1, 1, 150, '2013-04-02'),
    (2, 1, 100, '2013-04-02'),
    (3, 1, 500, '2013-04-04'),
    (2, 2, 400, '2013-04-04'),
    (1, 1, 300, '2013-04-08'),
    (3, 1, 200, '2013-04-08');

对于名为spenttime_week的viev中的数据应该出现:

+--------+----------+--------+------------+------+
| userid | serverid |  time  |  yearweek  | rank |
+--------+----------+--------+------------+------+
|     1  |       1  |   350  | '2013-W14' |   2  |
|     2  |       1  |   100  | '2013-W14' |   3  |
|     3  |       1  |   500  | '2013-W14' |   1  |
|     2  |       2  |   400  | '2013-W14' |   1  |
|     1  |       1  |   300  | '2013-W15' |   1  |
|     3  |       1  |   200  | '2013-W15' |   2  |
+--------+----------+--------+------------+------+

我知道如何生成不含排名的视图,我只有排名栏的麻烦...... 我怎样才能做到这一点?

//编辑 另外,这个专栏必须出现在viev中,我无法从该视图中选择生成它,因为我将使用它的app不允许...

3 个答案:

答案 0 :(得分:2)

首先,你需要创建第一个VIEW,它将同一周每个用户的花费时间相加:

clients

然后您可以创建视图:

CREATE VIEW total_spent_time AS
SELECT userid,
       serverid,
       sum(time) AS total_time,
       yearweek(day, 3) as week
FROM spenttime
GROUP BY userid, serverid, week;

请查看小提琴here

答案 1 :(得分:1)

你可以通过很多方式获得一周年专栏,为了清晰起见,这是一个快速懒惰的解决方案(因为我怀疑你正在努力解决这个问题)。但是,你可以在这里获得排名。 使用自联接获取数据集,包括时间值高于当前行的行,然后计算具有更高值的行:

这在MSSQL中要容易得多,这是我99%的时间生活的地方,你可以在那里使用RANK()函数。直到今天我还没有意识到在mysql中没有相应的东西。如果没有MS的帮助,可以找出如何获得相同结果的乐趣。

为上下文准备内容:

CREATE TABLE spenttime (userid int, serverid int, [time] int, [day] DATETIME)


CREATE TABLE weeklookup (weekname VARCHAR(10), weekstart DATETIME, weekend DATETIME)

INSERT INTO spenttime (userid, serverid, [time], [day]) VALUES
    (1, 1, 200, '2013-apr-01'),
    (1, 1, 150, '2013-apr-02'),
    (2, 1, 100, '2013-apr-02'),
    (3, 1, 500, '2013-apr-04'),
    (2, 2, 400, '2013-apr-04'),
    (1, 1, 300, '2013-apr-08'),
    (3, 1, 200, '2013-apr-08');

INSERT INTO weeklookup(weekname, weekstart, weekend) VALUES
     ('2013-w14', '01/apr/2013', '08/apr/2013'),
     ('2013-w15', '08/apr/2013', '15/apr/2013')


GO 
CREATE VIEW weekgroup AS 

SELECT    a.userid ,
                    a.serverid ,
                    a.[time] ,
                    w1.weekname
          FROM      spenttime a
                    INNER JOIN weeklookup w1 ON [day] >= w1.weekstart
                                                 AND [day] < w1.weekend
GO

选择视图的语句:

SELECT  wv1.userid ,
        wv1.serverid ,
        wv1.[time] ,
        wv1.weekname AS yearweek ,
        COUNT(wv2.[time]) + 1 AS rank
FROM    weekgroup wv1
        LEFT JOIN weekgroup wv2 ON wv1.[time] < wv2.[time]
               AND wv1.weekname = wv2.weekname
               AND wv1.serverid = wv2.serverid
GROUP BY wv1.userid ,
        wv1.serverid ,
        wv1.[time] ,
        wv1.weekname
ORDER BY wv1.weekname ,
        wv1.[time] DESC

答案 2 :(得分:0)

如果要存储排名,可以使用insert触发器。插入触发器将计算排名,如:

select count(*)
from spenttime_week w
where w.yearweek = new.yearweek and time >= new.time

但是,我不建议这样做,因为你必须创建一个update触发器,并修改已经插入的等级值。

而是使用SQL访问表,如:

select w.*,
       (select count(*) from spenttime_week w2 where w2.yearweek = w.yearweek and w2.time >= w.time
       ) as rank
from spenttime_week w

此SQL可能会有所不同,具体取决于您希望如何处理数据中的关系。出于性能原因,您的索引应至少为yearweek,并且可能位于yearweek, time