2

所以我有一个结构如下的 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 时间戳(一天的开始)。我想在我的数据库上创建一个视图,该视图将显示每个用户每周在服务器上花费的时间,但有一列显示该时间的排名,每周对每个服务器都是独立的。例如数据(为了澄清,我将day在此示例中使用日期格式 YMD 而不是 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');

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

+--------+----------+--------+------------+------+
| 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  |
+--------+----------+--------+------------+------+

我知道如何生成没有排名的视图,我只有排名列的问题......我怎样才能做到这一点?

//edit Additionaly,此列必须出现在 viev 中,我无法从该视图中生成它,因为我将使用它的应用程序不允许...

4

3 回答 3

2

首先,您需要创建第一个 VIEW 来汇总每个用户在同一周所花费的时间:

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;

然后你可以这样创建你的视图:

CREATE VIEW spenttime_week AS
 SELECT
  s1.userid,
  s1.serverid,
  s1.total_time,
  s1.week,
  count(s2.total_time)+1 AS rank
FROM
  total_spent_time s1 LEFT JOIN total_spent_time s2
  ON s1.serverid=s2.serverid
     AND s1.userid!=s2.userid
     AND s1.week = s2.week
     AND s1.total_time<=s2.total_time
GROUP BY  
  s1.userid,
  s1.serverid,
  s1.total_time,
  s1.week
ORDER BY
  s1.week, s1.serverid, s1.userid

请看这里的小提琴。

于 2015-09-16T20:36:57.427 回答
1

有很多方法可以获得 yearweek 专栏,这是一个快速的懒惰解决方案(因为我怀疑你正在为此苦苦挣扎)。但这是获得排名的方法。使用自联接获取包含时间值高于当前行的行的数据集,然后计算具有更高值的行:

这在 MSSQL 中要容易得多,我 99% 的时间都住在 MSSQL 中,您可以只使用 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
于 2015-09-16T11:22:36.013 回答
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.

于 2013-04-08T07:20:09.957 回答