LEFT JOIN with self table 只有第一行
LEFT JOIN with self table only first row
正在处理 MySQL、
我有这个 activity table 用户事件:
activity
hash_id | type | timestamp | user |
--------+----------+------------+-------+
abc123 | ASSIGN | 2015-09-01 | user1 |
456def | ASSIGN | 2015-09-02 | user2 |
ghi789 | ASSIGN | 2015-09-05 | user3 |
012jkl | ASSIGN | 2015-09-10 | user4
我希望获得 'ASSIGN' 活动的历史记录,告诉 userN,它何时被分配,以及何时通过分配给其他人而被取消分配。 (可能还有其他类型的活动,此处忽略)
像这样:
start | end | user
-----------+------------+-------
2015-09-01 | 2015-09-02 | user1
2015-09-02 | 2015-09-05 | user2
2015-09-05 | 2015-09-10 | user3
2015-09-10 | NA | user4
对于任何用户 N,属于另一个不同用户的未来 ASSIGN 事件意味着取消分配它。
如果对于某些用户 N 没有未来的 ASSIGN-to-a-different-user 事件,那么结束栏可能会说 'NA'。这意味着当前已分配 userN。
因此,我认为解决方案可能来自 activity table 与自身的 LEFT JOIN。但目前我只能得到一些令人困惑的活动历史记录,用户的每个时间戳都与 table 上的每个其他 activity 相关。
我得到:
start | end | user
-----------+------------+-------
2015-09-01 | 2015-09-02 | user1
2015-09-01 | 2015-09-05 | user1
2015-09-01 | 2015-09-10 | user1
2015-09-02 | 2015-09-05 | user2
2015-09-02 | 2015-09-10 | user2
2015-09-05 | 2015-09-10 | user3
2015-09-10 | NA | user4
我注意到 JOIN 正在检索 activity 和未来活动之间的所有关系,事实上,如果我可以检索 JOIN 的第一个结果,这就可以解决。这就是我被困的地方。
我目前正在玩两个可能的查询,都给我相同的结果::
这是我的第一次尝试:
SELECT a.timestamp AS start,
COALESCE(endac.timestamp,'NA') AS end,
a.user
FROM activity a
LEFT JOIN
(SELECT ac.timestamp, ac.groupkey, ac.assigneduserkey, ac.type
FROM activity jac
WHERE jac.type='ASSIGN'
) endac
ON (endac.user <> a.user AND endac.timestamp > a.timestamp)
WHERE a.type = 'ASSIGN'
另一个来自我在 LEFT JOIN only first row 阅读的内容:
SELECT a.timestamp AS start,
COALESCE(endac.timestamp,'NA') AS end,
a.user
FROM activity a
LEFT JOIN activity endac
ON (endac.hash_id = (SELECT jact.hash_id
FROM activity jact
WHERE jact.hash_id=endac.hash_id
AND jact.type = 'ASSIGN'
AND jact.user <> a.user
AND jact.timestamp > a.timestamp
LIMIT 1
)
)
WHERE a.type = 'ASSIGN'
有什么建议吗?我是否在正确的轨道上满足我的需求?如何只获取 JOIN 的第一行以便我可以获得正确的结果?
这个应该没那么复杂!
SELECT
plus.timestamp AS start,
IFNULL(MIN(minus.timestamp),'NA') AS end,
plus.user AS user
FROM
activity AS plus
LEFT JOIN activity AS minus
ON minus.timestamp>plus.timestamp
GROUP BY plus.timestamp
ORDER BY plus.timestamp
;
给出了预期的输出,但效率当然非常低。
正在处理 MySQL、
我有这个 activity table 用户事件:
activity
hash_id | type | timestamp | user |
--------+----------+------------+-------+
abc123 | ASSIGN | 2015-09-01 | user1 |
456def | ASSIGN | 2015-09-02 | user2 |
ghi789 | ASSIGN | 2015-09-05 | user3 |
012jkl | ASSIGN | 2015-09-10 | user4
我希望获得 'ASSIGN' 活动的历史记录,告诉 userN,它何时被分配,以及何时通过分配给其他人而被取消分配。 (可能还有其他类型的活动,此处忽略)
像这样:
start | end | user
-----------+------------+-------
2015-09-01 | 2015-09-02 | user1
2015-09-02 | 2015-09-05 | user2
2015-09-05 | 2015-09-10 | user3
2015-09-10 | NA | user4
对于任何用户 N,属于另一个不同用户的未来 ASSIGN 事件意味着取消分配它。
如果对于某些用户 N 没有未来的 ASSIGN-to-a-different-user 事件,那么结束栏可能会说 'NA'。这意味着当前已分配 userN。
因此,我认为解决方案可能来自 activity table 与自身的 LEFT JOIN。但目前我只能得到一些令人困惑的活动历史记录,用户的每个时间戳都与 table 上的每个其他 activity 相关。
我得到:
start | end | user
-----------+------------+-------
2015-09-01 | 2015-09-02 | user1
2015-09-01 | 2015-09-05 | user1
2015-09-01 | 2015-09-10 | user1
2015-09-02 | 2015-09-05 | user2
2015-09-02 | 2015-09-10 | user2
2015-09-05 | 2015-09-10 | user3
2015-09-10 | NA | user4
我注意到 JOIN 正在检索 activity 和未来活动之间的所有关系,事实上,如果我可以检索 JOIN 的第一个结果,这就可以解决。这就是我被困的地方。
我目前正在玩两个可能的查询,都给我相同的结果::
这是我的第一次尝试:
SELECT a.timestamp AS start,
COALESCE(endac.timestamp,'NA') AS end,
a.user
FROM activity a
LEFT JOIN
(SELECT ac.timestamp, ac.groupkey, ac.assigneduserkey, ac.type
FROM activity jac
WHERE jac.type='ASSIGN'
) endac
ON (endac.user <> a.user AND endac.timestamp > a.timestamp)
WHERE a.type = 'ASSIGN'
另一个来自我在 LEFT JOIN only first row 阅读的内容:
SELECT a.timestamp AS start,
COALESCE(endac.timestamp,'NA') AS end,
a.user
FROM activity a
LEFT JOIN activity endac
ON (endac.hash_id = (SELECT jact.hash_id
FROM activity jact
WHERE jact.hash_id=endac.hash_id
AND jact.type = 'ASSIGN'
AND jact.user <> a.user
AND jact.timestamp > a.timestamp
LIMIT 1
)
)
WHERE a.type = 'ASSIGN'
有什么建议吗?我是否在正确的轨道上满足我的需求?如何只获取 JOIN 的第一行以便我可以获得正确的结果?
这个应该没那么复杂!
SELECT
plus.timestamp AS start,
IFNULL(MIN(minus.timestamp),'NA') AS end,
plus.user AS user
FROM
activity AS plus
LEFT JOIN activity AS minus
ON minus.timestamp>plus.timestamp
GROUP BY plus.timestamp
ORDER BY plus.timestamp
;
给出了预期的输出,但效率当然非常低。