문제

좋은 날 모두.

이 환경이 있습니다. 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 초이며 베타의 마지막 로그인은이 수표 실행시 온라인 상태가되므로 무시할 수 있습니다. 따라서 "베타"는 하나의 항목 만 갖습니다.

쿼리를 통해 계산하는 방법이 있습니까? 아니면 "시간 온라인 시간"열을 추가하고 사용자 로그 아웃 할 때마다 Sistem이 온라인으로 얼마나 많은 시간을 소비했는지 계산하는 것이 더 낫습니까?

도움이 되었습니까?

해결책

MySQL에서 수행하려면 자체 합의가 필요합니다. MySQL에는 Rownum 기능이 내장되어 있지 않기 때문에 목에 고통이 있습니다. 그러나 여전히 가능합니다.

먼저 가상 테이블 시뮬레이션을 만들려면 하위 쿼리를 만들어야합니다. SELECT rownum, user, timestamp FROM login 우리가 이것을 좋아할 수 있습니다. http://sqlfiddle.com/#!2/bf6ef/2/0

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

다음으로, 우리는이 가상 테이블의 자체 합의를 사본 자체로 수행해야합니다. 이 결과 세트에서 원하는 것은 테이블의 모든 연속 행의 목록입니다. 그 쿼리는 헤어볼입니다 구조 안에 구조화 된 쿼리 언어. 그러나 그것은 작동합니다. 여기있어: 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:=@a+1 AS rownum, user, timestamp
         FROM (
             SELECT user, timestamp
               FROM login
           ORDER BY timestamp
              ) C,
          (SELECT @a:=0) s
        ) AS first
  JOIN (
       SELECT @b:=@b+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:=@a+1 AS rownum, user, timestamp
         FROM (
                   SELECT user, timestamp
                     FROM login
                 ORDER BY timestamp
                    ) C,
                (SELECT @a:=0) s
              ) AS first
        JOIN (
             SELECT @b:=@b+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에서 이런 종류의 연속 열 비교를하는 방식입니다.

다른 팁

이것으로 시도해보십시오 ... 문제의 해결책이 적습니다 ...

    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

:-) 월요일 만나요 !!!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top