检查每个组的列中是否存在值

Check whether value exists in column for each group

很难把我想做的事情用文字表达出来,所以搜索也很困难。

基本上我试图查看列中是否存在某个值,按组分区,然后向前传播该值。

在此示例中,我想检查用户是否已完成教程并设置一个继续前进的标志。

pk | user | ... | activity
 1 |    A | ... |  "login"
 2 |    A | ... |  "started_tutorial"
 3 |    A | ... |  "completed_tutorial"
 4 |    A | ... |  "some other activity"
 5 |    A | ... |  "logout"
 5 |    B | ... |  "login"
 6 |    B | ... |  "logout"

我觉得应该是这样的

select *,
    check(activity in ('completed_tutorial')) as completed_activity
    from tbl

但我认为我不能在 select 语句中使用 check,这将是一个常量标志,而不是仅在找到后才设置为 true。

我想要得到的例子:

pk | user | ... | activity               | completed_tutorial
 1 |    A | ... |  "login"               |                 0
 2 |    A | ... |  "started_tutorial"    |                 0
 3 |    A | ... |  "completed_tutorial"  |                 1
 4 |    A | ... |  "some other activity" |                 1
 5 |    A | ... |  "logout"              |                 1
 5 |    B | ... |  "login"               |                 0
 6 |    B | ... |  "logout"              |                 0

您可以使用 HAVING clause 筛选 SQL 个组。例如,您可以按用户及其 activity 对 table 进行分组,然后对其进行过滤以仅包含已完成教程的用户:

SELECT user FROM tbl
GROUP BY user, activity
HAVING activity = 'completed_tutorial';

编辑: OP 编辑​​了他们的问题后,这是我的新答案。在这里,我假设您的 table 有一个日期字段。

SELECT *, COALESCE(date >= (
    SELECT date FROM tbl WHERE activity = 'completed_tutorial'
    AND user = outertbl.user
), FALSE)
FROM tbl AS outertbl
ORDER BY date

请注意,此类查询在未优化时本质上是 N²,因此我建议您只从数据库中获取数据,然后在您的程序中对其进行处理。

你可以试试这样的

SELECT a.*, coalesce(b.completed, 0)
FROM tbl a 
LEFT JOIN (SELECT user, 1 completed 
           FROM tbl 
           WHERE user = a.user 
                 AND activity='completed_tutorial') b 
ON a.user = b.user AND b.pk >= a.pk

它假定最多有一行 activity='completed_tutorial' 并且用户标识 "session"。如果用户可以制作多个教程,则必须添加另一个字段。

我不确定这样做的速度,但是下面的解决方案呢?

SELECT
    user
    ,max(CASE
            WHEN activity = "completed_tutorial" THEN 1
            ELSE 0
            END) AS completed_tutorial
  FROM tbl
  GROUP BY user
 ;
SELECT user FROM tbl
GROUP BY user
HAVING COUNT(CASE WHEN activity = 'completed_tutorial' THEN 1 ELSE 0 END) = 1;

这会给你所有完成教程的用户,至少一次。

SELECT 来自 tbl 的用户 按用户分组 计数(当 activity = 'completed_tutorial' THEN 1 ELSE 0 END 时的情况)= 1; 这将为您提供所有完成教程的用户,恰好一次。