从数据库中获取唯一信息

时间:2015-11-02 07:07:42

标签: php mysql sql database

我的用户登录表为“登录”,其中包含与用户相关的所有详细信息,如登录日期(日期时间),姓名等。

表“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"

2 个答案:

答案 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'