1

我有一个表格,我可以在其中跟踪访问者在我的网站上所做的所有页面浏览量。现在我正在尝试将页面视图按访问分组。一次访问由同一个访问者 ID 完成,如果两次页面浏览时间间隔超过 60 分钟,我将其定义为两次单独访问。pageviewID 只是一个随机的

Id  visitorid   timestamp   page
1   1   2013-10-10 18:00    /
2   2   2013-10-10 18:10    /
3   2   2013-10-10 18:12    /about
4   1   2013-10-10 18:14    /contact
5   3   2013-10-10 18:34    /
6   3   2013-10-10 18:37    /contact
7   4   2013-10-10 20:12    /
8   1   2013-10-10 20:14    /about

我希望能够查询例如最后 5 次完整访问并获得如下结果:

Id  visitorid   timestamp   page    visitid
1   1   2013-10-10 18:00    /           1
4   1   2013-10-10 18:14    /contact    1
2   2   2013-10-10 18:10    /           2
3   2   2013-10-10 18:12    /about      2
5   3   2013-10-10 18:34    /           3
6   3   2013-10-10 18:37    /contact    3
7   4   2013-10-10 20:12    /           4
8   1   2013-10-10 20:14    /about      5

这个怎么做?我不知道从哪里开始构建查询。我希望我包含了足够的信息!

4

2 回答 2

0

我认为问题是这样的。SQL 可以同时处理多组事物。您会获得一组行并对其进行操作以更改信息或获取不同的信息或获取信息的摘要。您想要做的事情本质上需要一个一个地遍历项目。SQL 不会一一做任何事情。它只是不会那样做。

我认为您需要将信息从数据库中提取到其他工具中。然后做一些迭代的事情。然后您可以保存新信息并再次执行数据库操作。

说你有:

 Id  visitorid   timestamp   page    visitid
 1   1   2013-10-10 18:00    /           1
 4   1   2013-10-10 18:14    /contact    1
 2   2   2013-10-10 18:10    /           2
 3   2   2013-10-10 19:12    /about      2
 5   2   2013-10-10 19:17    /contact    2

您可以获取数据并将其传递给 perl 脚本或任何其他脚本。如果必须,您甚至可以在 awk 中执行此操作。该脚本将遍历行。它会按顺序查看访问者的时间。如果两次之间的间隔大于一小时,它将创建一个新的访问 ID 并将后续请求设置为该 ID。数据将变为:

 Id  visitorid   timestamp   page    visitid
 1   1   2013-10-10 18:00    /           1
 4   1   2013-10-10 18:14    /contact    1
 2   2   2013-10-10 18:10    /           2
 3   2   2013-10-10 19:12    /about      101
 5   2   2013-10-10 19:17    /contact    101

对于它找到一个小时过去的每一点,你的脚本可以生成 SQL,它说:

update mytable set visitid = 101 where visitId = 2 and timestamp >= '2013-10-10 19:12';

每次间隔大于一小时时,您都可以生成这样的 SQL 命令,即使在一个访问 ID 中有多个间隔时也是如此。

将该 SQL 传递回您的数据库。然后你可以在你的数据库中做一个正常的查询。

另一种选择是,如果访问已定义并且此时正在记录访问 ID,则让最初重新编码信息的事物通知已经有一个小时间隔并转到新的访问 ID。

简短的回答是 SQL 本身不能做所有事情。这就是为什么,例如,在 Oracle 中定义了 PL/SQL 语言。它适用于数据库行,但允许您执行诸如迭代之类的操作。

于 2013-10-11T20:41:02.980 回答
0

您实际上可以使用SQLite 窗口函数来执行此操作,它可以解决 Ray Kiddy 描述的“迭代”部分。

假设您的时间戳是简单的 unix 时间戳,这将计算每个访问者的每个页面视图之间的非活动时间:

SELECT
  utc_time,
  visitor_id,
  -- The window function: resolves the expression for the preceding row of the current partition
  LAG(utc_time) OVER (
    -- The window defition: Partitions all rows per visitor_id and orders each partition's rows by timestamps
    PARTITION BY visitor_id
    ORDER BY
      utc_time
  ) -- Substract the utc_time of the current row from the utc_time of the preceding row to get the time between rows
  - utc_time AS inactivity_time
FROM page_view
ORDER BY
  visitor_id,
  utc_time;

上述查询的结果可用于通过后续查询实际分配会话 ID。使用非活动时间大于所需阈值的那些行,如果是第一个会话,则为 NULL,您可以使用另一个窗口函数 (row_number) 来唯一标识会话,包括开始时间和下一个会话的开始时间:

SELECT
  -- Calculate the session id based on the visitor and the consecutive row number (we only handle session starts here)
  page_view.visitor_id || '-' || row_number() OVER(
    PARTITION BY page_view.visitor_id
    ORDER BY
      page_view.utc_time
  ) AS session_id,
  page_view.visitor_id,
  page_view.utc_time AS session_start_at,
  lead(utc_time) OVER(
    PARTITION BY page_view.visitor_id
    ORDER BY
      page_view.utc_time
  ) AS next_session_start_at
FROM (...) AS page_view
WHERE
  -- Filter for page views with an inactivity time greater 30 mins, these are session starts
  ABS(page_view.inactivity_time) > 30 * 60
  OR page_view.inactivity_time IS NULL;

鉴于此,您可能希望将结果存储在临时表中以保持清晰。

假设结果存储在“会话”表中,您最终可以通过将页面视图与其对应的会话相结合来计算一些有用的统计信息:

SELECT
  session_id,
  -- calculate the session duration
  ABS(
    MIN(page_view.utc_time) - MAX(page_view.utc_time)
  ) AS duration,
  -- show distinct paths per session
  COUNT(DISTINCT page_view.path)
FROM session
LEFT JOIN page_view ON page_view.visitor_id = session.visitor_id
  AND page_view.utc_time >= session.session_start_at
  AND (
    page_view.utc_time < session.next_session_start_at
    OR session.next_session_start_at IS NULL
  )
GROUP BY
  1

我建议从第一个查询开始并逐步提高,这有助于我了解发生了什么。

这里列出的大多数查询都来自这篇博文,我稍微调整了它们以在 SQLite 中工作。

于 2020-04-24T20:28:50.560 回答