【问题标题】:Multiple conditions (A and B) and not (C and D). How should the SQL query look like?多个条件(A 和 B)而不是(C 和 D)。 SQL 查询应该是什么样子?
【发布时间】:2022-07-30 21:36:33
【问题描述】:

假设我们在一个表中有一个电子商店和所有用户的活动。 events 表如下所示:

id user_id type time comment
1 1 visit_site 2022-04-07 14:08
1 1 add_item_to_cart 2022-04-07 14:17
1 1 add_item_to_cart 2022-04-07 14:17
1 1 checkout 2022-04-07 14:22
1 1 pay 2022-04-07 14:25
1 2 visit_site 2022-04-07 14:30
1 2 add_item_to_cart 2022-04-07 14:40
1 2 add_item_to_cart 2022-04-07 14:44
1 2 checkout 2022-04-07 14:47
1 2 pay 2022-04-07 14:50

所以有多种事件类型,它们有时间戳(当它发生时)和作为参与者的用户。

假设我想查找所有将商品添加到购物车并在第二天购买的用户。 我会假设 SQL 查询应该是

SELECT DISTINCT
  user_id
FROM
  user_event
WHERE
  (type = 'add_item_to_cart' AND time BETWEEEN '2022-04-07 00:00' AND '2022-04-08 00:00') AND
  (type = 'buy' AND time BETWEEEN '2022-04-08 00:00' AND '2022-04-09 00:00')

现在,我明白了上面的条件基本上等于:

WHERE
  type = 'add_item_to_cart' AND time BETWEEEN '2022-04-07 00:00' AND '2022-04-08 00:00' AND
  type = 'buy' AND time BETWEEEN '2022-04-08 00:00' AND '2022-04-09 00:00'

这将始终返回空结果,因为我们将两个条件应用于日期范围不相交的 time 列。

所以我有 3 个问题

  1. 如何重写查询,以便获得在 1 个日期范围内将商品添加到购物车并在另一个日期范围内购买的客户?
  2. 上述条件实际上与添加到购物车后近 2 天的购买相匹配,即“2022-04-07 00:01” - 添加到购物车,“2022-04-08 23:58” - 已购买。如何制定与前一个条件相关的条件,即从最后结账日期起严格小于 1 天匹配购买(具有匹配的用户 ID)?
  3. 有没有办法强制事件与同一用户相关,以便查询不会返回在其他人(使用不同的user_id)将商品添加到购物车后

【问题讨论】:

  • 我删除了冲突的 DBMS 标签。请为您真正使用的数据库产品添加一个标签。
  • DISTINCT 不是函数,它是一个集合量词,是SELECT DISTINCT 的一部分。跳过那些多余的括号,直接写SELECT DISTINCT user_id FROM...,让代码更清晰——适合所有人。
  • 您可以在您的事件表中添加一个新的字段(例如 ref_order_id),它可以对相同的事件进行分组。然后您可以根据pay 操作轻松获得所需的结果。

标签: sql


【解决方案1】:

您可以尝试将SELF JOIN 应用于同一用户在相差一天的交易上,而不是在同一个SELECT 中使用WHERE 语句:

SELECT DISTINCT
    t1.id,
    t1.user_id,
    t1.time AS time1,
    t1.type AS type1,
    t2.time AS time2,
    t2.type AS type2
FROM 
    user_event t1 
INNER JOIN 
    user_event t2
ON 
    t1.user_id = t2.user_id
AND 
    DATEDIFF(t2.time, t1.time) = 0
WHERE 
    t1.type = 'add_item_to_cart'
AND 
    t2.type = 'pay'

此解决方案可以回答您的所有问题。你可以在这里找到一个小提琴:https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=3066b711f72ce7444859be1a824d9eb3。 这个小提琴的输入行包含三种用户:

  1. 当天购买的用户,
  2. 后天购买的用户(目标用户),
  3. 两天后购买的用户。

【讨论】:

  • 那么,如果我想找到有 3 个事件的用户,我需要两个 join 吗?
  • @Andrew_Lvov 此解决方案与您帖子中的三个高度具体的问题有关,涉及两个事件“add_item_to_cart”和“buy”。 3 个事件需要两个连接吗?也许也许不是:这真的取决于你在寻找什么。我可以肯定地说,如果你想要一个“干净的操作”,你不能避免至少一个自加入(可能会避免一个以上)。您能否提供一个完整的通用示例来说明您需要做什么?
  • 如果你想让它在事件上通用,你也可以将WHERE条件设置为t1.time <> t2.time。它对您正在寻找的东西有用吗?
  • 比这里发布的解决方案稍微复杂一些。参考这个小提琴:dbfiddle.uk/…。一旦你得到events_inside_24h 表,你就可以玩条件,不管你的任务有多复杂。
  • 非常感谢!这让事情变得更加清晰)
猜你喜欢
  • 2012-01-27
  • 2015-11-20
  • 2011-06-13
  • 1970-01-01
  • 1970-01-01
  • 2019-08-07
  • 1970-01-01
  • 2013-06-23
  • 2013-01-27
相关资源
最近更新 更多