获取每天的可用时间

时间:2018-09-16 08:37:02

标签: mysql sql

我需要让用户每天在MySQL中的访问持续时间。 我有这样的桌子:

user_id,date,time_start, time_end
1, 2018-09-01, 09:00:00, 12:30:00
2, 2018-09-01, 13:00:00, 15:10:00
1, 2018-09-03, 09:30:00, 12:30:00
2, 2018-09-03, 13:00:00, 15:10:00

并需要获得:

user_id,2018-09-01_duration,2018-09-03_duration
1,03:30:00,03:00:00
2,02:10:00,02:10:00

因此各列需要保持动态,因为某些日期可能会丢失(2018-09-02)。 每天可能有一个查询没有显式联接(某些日子可能为空)吗?

更新#1

是的,我可以在应用程序端生成列,但是我仍然遇到可怕的查询

SELECT user_id, d1.dt AS "2018-08-01_duration", d2.dt AS "2018-08-03_duration"...
FROM (SELECT 
            user_id,
            time_format(TIMEDIFF(TIMEDIFF(time_out,time_in),time_norm),"%H:%i") AS dt 
        FROM visits 
        WHERE date = "2018-09-01") d1
        LEFT JOIN(
        SELECT 
            user_id,
            time_format(TIMEDIFF(TIMEDIFF(time_out,time_in),time_norm),"%H:%i") AS dt 
        FROM visits 
        WHERE date = "2018-09-03") d3 
        ON users.id = d3.user_id...

更新#2

是的,数据类似

select user_id, date, SEC_TO_TIME(SUM(TIME_TO_SEC(time_out) - TIME_TO_SEC(time_in))) as total
from visits
group by user_id, date;

是正确的,但在这种情况下,用于用户的数据会保持一致。我希望能有这样一种方式,让我的用户行和带有日期的列(如上面的示例)

4 个答案:

答案 0 :(得分:1)

尝试这样的事情:

select user_id, date, sum(time_end - time_start) 
from table
group by user_id, date;

您将需要进行一些调整,因为您没有提到RDBMS提供程序,但是它应该为您提供一个清晰的思路。

答案 1 :(得分:1)

在MySQL中没有动态的方法来使用数据透视,但是您可能会use the following用于您的情况:

create table t(user_id int, time_start timestamp, time_end timestamp);
insert into t values(1,'2018-09-01 09:00:00', '2018-09-01 12:30:00');
insert into t values(2,'2018-09-01 13:00:00', '2018-09-01 15:10:00');
insert into t values(1,'2018-09-03 09:30:00', '2018-09-03 12:30:00');
insert into t values(2,'2018-09-03 13:00:00', '2018-09-03 15:10:00');

select min(q.user_id) as user_id, 
       min(CASE WHEN (q.date='2018-09-01') THEN q.time_diff END) as '2018-09-01_duration',
       min(CASE WHEN (q.date='2018-09-03') THEN q.time_diff END) as '2018-09-03_duration'
  from
  (
   select user_id, date(time_start) date,
          concat(concat(lpad(hour(timediff(time_start, time_end)),2,'0'),':'),
          concat(lpad(minute(timediff(time_start, time_end)),2,'0'),':'),
          lpad(second(timediff(time_start, time_end)),2,'0')) as time_diff      
     from t
  ) q
  group by user_id;

答案 2 :(得分:0)

通过查询可以解决您的问题。查询是动态的,您可以对其进行改进。 我使用TSQL进行查询,您可以在MySQL中使用该想法。

declare
    @columns    as nvarchar(max),
    @query      as nvarchar(max)

select
    @columns    =
    stuff
    ((
            select
            distinct
                ',' + quotename([date]) 
            from
                table_test
            for xml path(''), type
    ).value('.', 'nvarchar(max)'), 1, 1, '')

--select    @columns

set @query =
'with
    cte_result
as
(
    select
        [user_id]   ,
        [date]      ,
        time_start  ,
        time_end    ,
        datediff(minute, time_start, time_end)  as duration
    from
        table_test
)
select
    [user_id], ' + @columns + '
from 
(
    select
        [user_id]   ,
        [date]      ,
        duration
    from
        cte_result
)
    sourceTable
pivot 
(
    sum(duration)
    for [date] in (' + @columns + ')
)
    pivotTable'


execute(@query)

答案 3 :(得分:0)

如果知道结果集中所需的日期,则不需要动态查询。您可以只使用条件聚合:

select user_id,
    SEC_TO_TIME(SUM(CASE WHEN date = '2018-09-01' THEN TIME_TO_SEC(time_out) - TIME_TO_SEC(time_in))) as total_20180901,
    SEC_TO_TIME(SUM(CASE WHEN date = '2018-09-02' THEN TIME_TO_SEC(time_out) - TIME_TO_SEC(time_in))) as total_20180902,
    SEC_TO_TIME(SUM(CASE WHEN date = '2018-09-03' THEN TIME_TO_SEC(time_out) - TIME_TO_SEC(time_in))) as total_20180903
from visits
group by user_id;

如果不知道结果集中所需的日期,则仅需要动态SQL。在这种情况下,我建议遵循与您想要的日期相同的结构。