我的用户登录表为“登录”,其中包含与用户相关的所有详细信息,如登录日期(日期时间),姓名等。
表“users”,“user_category”包含特定用户类别的用户ID,例如worker,owner。
用户可以在一天内多次登录。我想获取最近一次关于用户的登录信息,如登录日期和时间,所以我应用“distinct”它工作正常,因为我使用CAST将log_time从datetime转换为date(log_time作为日期)。但我也想要时间。
请建议一些方法而不是我使用“group by”它给出了多个记录。 这是我试过的查询
(select distinct users.users_desc as name,login.user_id,CAST(log_time AS DATE) as log_time
from login,users,user_category
where (((log_time BETWEEN '2015-06-01' AND '2015-10-01') OR (DATE(`log_time`)='2015-10-01')))
and login.user_id=users.users_id and
user_category.category_desc='WORKERS' and
user_category.category_id=users.cat_id )
示例:
This how my login table look like
name user_id login_time
"A1-C" "userId_1" "2015-06-04 13:01:22"
"A1-C" "userId_1" "2015-06-04 14:00:00"
"A1-C" "userId_1" "2015-06-12 00:00:00"
"A2-C" "userId_2" "2015-06-04 13:01:22"
"A2-C" "userId_2" "2015-06-04 14:01:00"
"A2-C" "userId_2" "2015-06-12 10:00:00"
I want output as :
name user_id date time
"A1-C" "userId_1" "2015-06-04" " 14:00:00"
"A1-C" "userId_1" "2015-06-12" "00:00:00"
"A2-C" "userId_2" "2015-06-04" "14:01:00"
"A2-C" "userId_2" "2015-06-12" "10:00:00"
答案 0 :(得分:0)
让我们从您的查询开始进行一些转换(因此它的形式我更适合;-))。
首先,使格式更详细
(
select distinct
users.users_desc as name,
login.user_id,
CAST(log_time AS DATE) as log_time
from
login,
users,
user_category
where
(
(
(
log_time BETWEEN '2015-06-01' AND '2015-10-01')
OR (DATE(`log_time`)='2015-10-01'
)
)
)
and login.user_id=users.users_id
and user_category.category_desc='WORKERS'
and user_category.category_id=users.cat_id
)
...between ... OR date(...)
部分可以通过
log_time BETWEEN '2015-06-01 00:00:00' AND '2015-10-01 23:59:59'
然后可以删除所有这些括号。同时点击distinct
,您的查询就像
select
users.users_desc as name,
login.user_id,
CAST(log_time AS DATE) as log_time
from
login,
users,
user_category
where
log_time BETWEEN '2015-06-01 00:00:00' AND '2015-10-01 23:59:59'
and login.user_id=users.users_id
and user_category.category_desc='WORKERS'
and user_category.category_id=users.cat_id
现在我们将隐式转换为显式JOIN
SELECT
u.users_desc as name,
l.user_id,
CAST(l.log_time AS DATE) as log_time
FROM
login as l
JOIN
users as u
ON
l.user_id=u.users_id
JOIN
user_category as c
ON
u.cat_id=c.category_id
where
log_time BETWEEN '2015-06-01 00:00:00' AND '2015-10-01 23:59:59'
AND user_category.category_desc='WORKERS'
(我还没有测试过这个查询,所以请检查一下它是否仍在运行 - execpt它现在返回所有登录因为缺少distinct
)
现在我们申请MySQL 5.7 Reference Manual - 3.6.4 The Rows Holding the Group-wise Maximum of a Certain Column。我选择使用LEFT JOIN和IS_NULL的第三个版本(优化器对这样的查询非常好) 您希望登录表的组最大化。 “基本查询”(没有其他两个表)将是
SELECT
l1.user,
l1.log_time
FROM
login as l1
LEFT JOIN
login as l2
ON
l1.user_id=l2.user_id
AND l1.log_time < l2.log_time
WHERE
l2.log_time IS NULL
但显然你想要在给定范围内每天按组分组最大值。所以我们为“分组”添加了另一个JOIN条件(这可能是查询性能的最大压力)
SELECT
l1.user,
l1.log_time
FROM
login as l1
LEFT JOIN
login as l2
ON
l1.user_id=l2.user_id
AND Date(l1.log_time) = Date(l2.log_time)
AND l1.log_time < l2.log_time
WHERE
l2.log_time IS NULL
现在让我们将其纳入“真正的”查询。
SELECT
u.users_desc as name,
l1.user_id,
l1.log_time as log_time
FROM
login as l1
LEFT JOIN
login as l2
ON
l1.user_id=l2.user_id
AND Date(l1.log_time) = Date(l2.log_time)
AND l1.log_time < l2.log_time
JOIN
users as u
ON
l1.user_id=u.users_id
JOIN
user_category as c
ON
u.cat_id=c.category_id
WHERE
l1.log_time BETWEEN '2015-06-01 00:00:00' AND '2015-10-01 23:59:59'
AND l2.log_time IS NULL
AND c.category_desc='WORKERS'
[两个注释:a)我删除了CAST(作为日期)和b)再次完全未经测试,我通常在盲目构建这些查询时犯错...请提供样本数据作为有效的INSERT INTO ...
语句进行测试]
答案 1 :(得分:0)
select * from users a
left join user_category b on b.category_id = a.cat_id
left join (
-- this subquery will return latest row on each user_id in range log_time
select * from (
select * from login
where log_time >= '2015-06-01' AND log_time <='2015-10-01'
order by log_time desc
) c GROUP BY users_id
) c on c.user_id = a.user_id
where b.category_desc='WORKERS'