mysql - 使用 MIN() 连接,其中 MIN() 大于连接左侧的值

标签 mysql sql postgresql

我正在尝试对(几个)SQL 数据库中的现有数据负载进行一些转换分析。

数据结构本身非常简单。它只是一个 Actor 列表(比如 user_id)和他们所做的事情的名称。它看起来像这样(还有其他数据,但不会在此查询中使用):

CREATE TABLE views(
    project_id integer not null,
    name varchar(128) not null,
    datetime timestamp not null,
    actor varchar(256) not null
)

目标是标准转化分析内容。执行 Action A,然后执行 B、C、D、E 等的人数,以及步骤之间的平均时间。

为了清楚起见,漏斗步骤规定了顺序,但不规定排他性。例如,寻找名字 A、B、C 的漏斗应该包括一个序列为 B、A、B、D、C 的 Actor (因为其中包含 A,然后是 B,然后是 C,即使有之间的步骤)。

目前我正在使用以下内容查询此表(每个连接代表转换漏斗中的下一步):

SELECT count(actor), count(span2), avg(span2), count(span3), avg(span3), count(span4), avg(span4), count(span5), avg (span5)
FROM
(
    SELECT e1.actor, 
        DATEDIFF(SECOND, MIN(e1.datetime), MIN(e2.datetime)) AS span2,
        DATEDIFF(SECOND, MIN(e2.datetime), MIN(e3.datetime)) AS span3,
        DATEDIFF(SECOND, MIN(e3.datetime), MIN(e4.datetime)) AS span4,
        DATEDIFF(SECOND, MIN(e4.datetime), MIN(e5.datetime)) AS span5
    FROM views AS e1
    LEFT JOIN (SELECT actor, MIN(datetime) as datetime FROM views WHERE name = 'Action 2' group by actor) as e2 ON e1.actor = e2.actor AND e2.datetime > e1.datetime
    LEFT JOIN (SELECT actor, MIN(datetime) as datetime FROM views WHERE name = 'Action 3' group by actor) as e3 ON e1.actor = e3.actor AND e3.datetime > e2.datetime
    LEFT JOIN (SELECT actor, MIN(datetime) as datetime FROM views WHERE name = 'Action 4' group by actor) as e4 ON e1.actor = e4.actor AND e4.datetime > e3.datetime
    LEFT JOIN (SELECT actor, MIN(datetime) as datetime FROM views WHERE name = 'Action 5' group by actor) as e5 ON e1.actor = e5.actor AND e5.datetime > e4.datetime
    WHERE e1.project_id = 1 and e1.name = 'Action 1'
    GROUP BY e1.actor
) AS aggregates

这在数据集上相当快(10M 行<1s)。问题是这实际上并不是正确的结果。子选定的连接每次都要求 MIN(datetime)。如果 Actor 序列按照 B、A、B 的顺序发生,则不会被计数,因为 MIN(A) 大于 MIN(B)。

给定一组执行了一系列 View 的 Actor ,我需要检查每个 Actor 是否执行了 View A,然后执行了 View B,然后执行了 View C,无论他们在执行过程中执行了任何步骤中间。 B、A、B、C 合格、A、B、B、C 合格、A、B、Z、C 合格、A、Z、C 不合格

要“正确”查询此内容,我可以删除子联接中的 MIN(datetime),并在联接外部执行 MIN()。然而,这需要非常长的时间,因为每个漏斗步骤的每行都会连接多次(步骤通常不按顺序重复)。在这种情况下,叉积是巨大的——查询规划器表示有 21 万亿行! (21,666,755,307,950,608)。这显然不再是 1 秒以下的查询。

我想要实现的是一个连接,其中连接发生在 MIN 值上,但 MIN 值是“MIN 值大于前一个连接步骤”。 IE。因此,对于步骤 A 到 B,B.datetime 是仍大于 A.datetime 的单个 MIN B.datetime。类似于(无效的 SQL!):

.... 
LEFT JOIN (SELECT actor, datetime FROM views WHERE name = 'Action 2') as e2 
ON e1.actor = e2.actor AND e2.datetime > e1.datetime HAVING MIN(e.datetime)
....

关于如何实现这一目标有什么建议吗?

如果合适的话,特定于 MySQL 或 PostgreSQL 的函数都可以。

最佳答案

我建议只查看所有过渡时间。以下是如何在 SQL 中执行此操作:

SELECT prevName, name, count(*) as NumTransitions,
       avg(DATEDIFF(SECOND, "datetime", prevdatetime))
FROM (SELECT e1.actor, "datetime", name,
             lag(name) over (partition by actor order by "datetime") as prevName,
             lag("datetime") over (partition by actor order by "datetime") as prevDateTime
      FROM views AS e1
      WHERE e1.project_id = 1 
     ) t
GROUP BY prevName, name;

如果您想要每次转换的“ Actor ”数量,可以添加 count(distinct actor)

关于mysql - 使用 MIN() 连接,其中 MIN() 大于连接左侧的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21765409/

相关文章:

SQL 查询错误或者它可能是什么?

mysql - PhpMyAdmin 问题 'phpmyadmin.pma_table_uiprefs' 不存在

mysql - 我是否必须将数据库连接/初始化放在 FCGI 循环之外才能利用 Perl 中的 FastCGI?

sql - 选择查询具有给定值的行的百分比?

sql - 在 Postgresql 中如何加速子字符串查询

java - Hibernate 中的 PostgreSQL 网络类型

php - 将点插入启用 PostGis 的 Postgres 数据库

mysql - 表之间的差异

mysql - 多余的外键?

Mysql 存储 url(不是 http)