質問

良い一日。

私はこの環境を持っています: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秒であり、このチェックの実行時にオンラインになるため、ベータの最後のログインは無視できます。したがって、「ベータ」には1つのエントリしかありません。

クエリでそれを計算する方法はありますか?または、「オンライン時間」という列を追加し、ユーザーがオンラインでどのくらいの時間を費やしたかをログアウトするたびに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