Получить продолжительность времени за каждый доступный день - PullRequest
0 голосов
/ 16 сентября 2018

Мне нужно получить продолжительность посещений пользователей за каждый день в 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 голосов
/ 16 сентября 2018

Если вы знаете нужные даты в наборе результатов, вам не нужен динамический запрос. Вы можете просто использовать условное агрегирование:

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 требуется только в том случае, если вы не знаете желаемых дат в наборе результатов. В этом случае я бы предложил придерживаться той же структуры с датами, которые вы хотите.

0 голосов
/ 16 сентября 2018

Нет динамического способа использовать разворот в MySQL, но вы можете использовать следующее для вашего случая:

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;
0 голосов
/ 16 сентября 2018

По запросу вы можете решить вашу проблему. запрос является динамическим, и вы можете улучшить его. я использую 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)
0 голосов
/ 16 сентября 2018

Попробуйте что-то вроде этого:

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

Вам потребуется внести некоторые изменения, поскольку вы не упомянули поставщика RDBMS, но он должен дать вам четкое представление о том, как это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...