2013-11-07 2 views
1

Добрый день.расчеты с истекшим временем на таблице mysql

У меня есть эта среда: на Mysql db, каждый раз, когда пользователь входит в систему на сайте, создается новая строка с именем и временем входа в систему. Поскольку система является взаимной эксклюзивностью, в данный момент будет только пользователь, и если новый пользователь прибудет, один из зарегистрированных отключится.

Теперь они попросили меня рассчитать общее время всех пользователей в системе, поэтому в основном я должен суммировать все различия во времени с логином и его следующей.

user |  timestamp  | 
------------------------------ 
alpha | 2013-01-19 03:14:07 
beta | 2013-01-20 11:24:04 
alpha | 2013-01-21 02:11:37 
alpha | 2013-01-21 03:10:31 <---- a user could login twice, it is normal 
gamma | 2013-01-21 11:24:04 
beta | 2013-01-21 11:25:00 

Я хотел бы спросить ваше мнение, так как есть много логинов, что это лучший способ, чтобы вычислить общее авторизовались времени пользователя? в этом примере «гамма» будет иметь время входа в систему 56 секунд, и последний логин бета-версии может быть проигнорирован, так как он будет в сети во время выполнения этой проверки. поэтому «бета» будет иметь только одну запись.

есть способ рассчитать его с помощью запроса? или лучше добавить столбец «время в сети», и пусть система вычисляет каждый раз, когда пользователь выходит из системы, сколько времени потрачено в Интернете?

+2

Можете ли вы быть уверены, что разница в логинах - это время входа в систему? Что делать, если пользователь выходит из системы и не работает какое-то другое время? – kero

+1

это выполнимо в mysql, но проще в php. просто заберите все строки, упорядоченные по метке времени, а затем начните выполнять «текущую временную метку строки» - отметку времени предыдущей строки, если имя пользователя отличается », чтобы получить промежутки между входами. –

+0

Да, допустим, если пользователь выйдет из системы и ни один вход в систему, система все равно будет занята. –

ответ

1

Для этого требуется самоподключение, если вы хотите сделать это в MySQL. Это боль в шее, чтобы сделать самостоятельное объединение, потому что MySQL не имеет встроенной функции rownum. Но это все еще выполнимо.

Во-первых, нам нужно создать подзапрос, чтобы создать виртуальную таблицу, имитирующую SELECT rownum, user, timestamp FROM login, которую мы можем сделать следующим образом. http://sqlfiddle.com/#!2/bf6ef/2/0

SELECT @a:[email protected]+1 AS rownum, user, timestamp 
    FROM (
     SELECT user, timestamp 
      FROM login 
     ORDER BY timestamp 
    ) C, 
    (SELECT @a:=0) s 

Далее нам нужно сделать автообъединение этой виртуальной таблицы на копию самого себя. В этом наборе результатов мы хотим видеть список всех последовательных пар строк в таблице. Этот запрос является hairball - он ставит структурированный в структурированный язык запросов. Но это работает. Вот оно: http://sqlfiddle.com/#!2/bf6ef/4/0

SELECT first.user AS fuser, 
     first.timestamp AS ftimestamp, 
     second.user AS suser, 
     second.timestamp as stimestamp, 
     TIMESTAMPDIFF(SECOND, first.timestamp, second.timestamp) AS timeloggedin 

    FROM (
     SELECT @a:[email protected]+1 AS rownum, user, timestamp 
     FROM (
      SELECT user, timestamp 
       FROM login 
      ORDER BY timestamp 
      ) C, 
      (SELECT @a:=0) s 
     ) AS first 
    JOIN (
     SELECT @b:[email protected]+1 AS rownum, user, timestamp 
     FROM (
      SELECT user, timestamp 
       FROM login 
      ORDER BY timestamp 
      ) C, 
      (SELECT @b:=0) s 
     ) AS second ON first.rownum+1 = second.rownum 

Весь трюк для сравнения последовательных строк является шаблон запроса

SELECT (virtual_table) AS first 
    JOIN (virtual_table) AS second ON first.rownum+1 = second.rownum 

. Элемент rownum + 1 = rownum собирает строки с последовательными номерами строк вместе.

Далее мы должны суммировать результат этого запроса, чтобы получить общее время входа для каждого пользователя. Это будет работать так:

SELECT user, SUM(timeloggedin) AS timeloggedin 
    FROM (
      /* the self-joined query */ 
     ) AS selfjoin 
    GROUP BY user 
    ORDER BY user 

Это выглядит следующим образом: http://sqlfiddle.com/#!2/bf6ef/5/0

Это весь запрос, вместе взятые.

SELECT user, SUM(timeloggedin) AS timeloggedin 
    FROM (
     SELECT first.user AS user, 
      TIMESTAMPDIFF(SECOND, first.timestamp, second.timestamp) AS timeloggedin 
     FROM (
      SELECT @a:[email protected]+1 AS rownum, user, timestamp 
     FROM (
        SELECT user, timestamp 
        FROM login 
       ORDER BY timestamp 
        ) C, 
       (SELECT @a:=0) s 
      ) AS first 
     JOIN (
      SELECT @b:[email protected]+1 AS rownum, user, timestamp 
       FROM (
        SELECT user, timestamp 
        FROM login 
       ORDER BY timestamp 
        ) C, 
       (SELECT @b:=0) s 
      ) AS second ON first.rownum+1 = second.rownum 
     ) AS selfjoin 
    GROUP BY user 
    ORDER BY user 

Это не настоящая интуиция для тех, кто привык к процедурным, алгоритмическим, мышления. Но так вы сравниваете сравнение последовательностей в SQL.

+0

хорошо, хорошо, я действительно не могу следовать за вами по всему коду, я сделаю несколько попыток и опубликую результат, но кстати на данный момент это лучшее решение: D –

+0

omg. он работает гладко, как шелк, спасибо много. Теперь остальная часть вечера поймет, что я сделал: D –

+0

Выяснение того, как работают запросы на самостоятельное присоединение, определенно стоит ваших усилий, если вы собираетесь использовать много SQL. Удачи! –

1

попробовать с этим ... больше или меньше есть решение вашей проблемы ...

CREATE TABLE `matteo` (
     `user` varchar(20) DEFAULT NULL, 
     `timestamp` int(11) DEFAULT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

    INSERT INTO matteo(user, `timestamp`) VALUES ('alpha', 7); 
    INSERT INTO matteo(user, `timestamp`) VALUES ('beta', 9); 
    INSERT INTO matteo(user, `timestamp`) VALUES ('alpha', 17); 
    INSERT INTO matteo(user, `timestamp`) VALUES ('alpha', 27); 
    INSERT INTO matteo(user, `timestamp`) VALUES ('gamma', 77); 
    INSERT INTO matteo(user, `timestamp`) VALUES ('beta', 97); 

    select a.*,b.*,b.`timestamp`-a.`timestamp` as delta 
    from 
    (SELECT @rownum := @rownum + 1 AS id,t.* 
      FROM matteo t,(SELECT @rownum := 0) r) a 
    join 
    (SELECT @rownum2 := @rownum2 + 1 AS id,t.* 
      FROM matteo t,(SELECT @rownum2 := 0) r) b 
    where a.id=b.id-1 

:-) посмотреть U понедельник !!!

Смежные вопросы