我正在运行MySQL服务器。在我的数据库中,我有一个用于记录页面请求的表:
CREATE TABLE IF NOT EXISTS `log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userId` smallint(5) NOT NULL,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`page` varchar(127) NOT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
我想获取日志列表,这样只显示访问某个页面的任何用户的最后五个记录。例如,如果某个用户已访问某个页面七次,则仅显示最后五个记录。除此之外,查询应返回所有记录。
我提出了以下问题:
SELECT *
FROM `log`
WHERE `time` >
(SELECT `time` FROM `log` as l
WHERE `l`.`userId`=`log`.`userId` AND `l`.`page`=`log`.`page`
ORDER BY `time` DESC LIMIT 5,1)
ORDER BY `time` DESC
子查询应该选择第五条记录。这很好用。但是,当用户没有访问某个页面超过五次时,不会返回任何内容,因为子查询无法找到结果(我认为)。我怎样才能使它适用于那种情况呢?
答案 0 :(得分:1)
首先,我刚学到了一些东西。 MySQL在limit
的子查询中不允许in
,我认为这扩展到了其他类似的操作(参见documentation)。但是,显然这是有效的。
注意:以下两项工作均不适用。
此版本可能有效:
WHERE `time` > (SELECT MIN(`time`)
FROM (SELECT time
FROM `log` l
WHERE `l`.`userId` = `log`.`userId` AND `l`.`page` = `log`.`page`
ORDER BY `time` DESC
LIMIT 5
) l
)
您也可以尝试这种表述:
WHERE `time` > ANY (SELECT time
FROM `log` l
WHERE `l`.`userId` = `log`.`userId` AND `l`.`page` = `log`.`page`
ORDER BY `time` DESC
LIMIT 5
)
我不确定子查询中对LIMIT
的限制是否适用于ANY
关键字。
编辑:
由于MySQL的限制,上述两种方法均无效。假设没有太多匹配,以下内容应该有效:
WHERE `time` > (SELECT TIME(SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(time ORDER BY time DESC), ',', 5), ',' -1))
FROM `log` l
WHERE `l`.`userId` = `log`.`userId` AND `l`.`page` = `log`.`page`
)
这会使用group_concat()
/ substring_index()
技巧。我不喜欢这个解决方案,但它在技术上应该可以工作,除非你在一个组中有这么多匹配超过group_concat()
的长度限制(总是可以设置为更高的值)。我确实想知道是否有更好的方法,只使用where
子句。
作为注释:执行此类操作的最有效方法通常是使用变量来枚举行。
答案 1 :(得分:0)
LIMIT 5,1
表示:
跳过5条记录,然后取1
因此,如果记录少于6条,则不会返回任何结果。