如何将不带过滤器的子查询连接到带过滤器的查询?

时间:2020-02-28 16:45:44

标签: sql sql-server

我有一个类似于下面简化查询的查询。

SELECT
  Users.ID,
  Registrations.Timestamp
FROM
  Users,
  Registrations
WHERE
  Users.ID = Registrations.UserID AND
  Registrations.Date >= '2020-02-27'
ORDER BY
  Users.ID,
  Registrations.Timestamp;

我要计算第三列Type,其值分别为entrydeparture,如下所示:

ID  | Timestamp           | Type
----+---------------------|----------
1   | 2020-02-27 05:43:24 | entry
1   | 2020-02-27 13:48:47 | departure
1   | 2020-02-28 05:44:38 | entry
1   | 2020-02-28 13:50:11 | departure
2   | 2020-02-27 13:44:41 | entry
2   | 2020-02-27 21:47:54 | departure
2   | 2020-02-28 13:40:16 | entry
2   | 2020-02-28 21:52:57 | departure
3   | 2020-02-27 05:46:20 | departure
3   | 2020-02-28 21:44:05 | entry
3   | 2020-02-28 05:47:18 | departure

它的计算方式是通过计算直至该注册的注册数量(不使用Date过滤器)。如果结果计数为奇数,则将其视为entry,否则为departure

在该示例中,用户号3以departure开头,因为即使它是第一个注册(奇数),但没有Date过滤器,它也是一个偶数。

我尝试使用子查询,但无法弄清楚如何仅计算Timestamp而不是全部计数。

SELECT
  Users.ID,
  Registrations.Timestamp,
  CASE WHEN
    (
      SELECT
        COUNT(Registrations.Timestamp)
      FROM
        Registrations
      WHERE
        Registrations.UserID = OuterUsers.ID AND
        Registrations.Timestamp <= OuterRegistrations.Timestamp
    ) % 2 = 0 THEN
    'departure'
  ELSE
    'entry'
  END AS Type
FROM
  Users,
  Registrations
WHERE
  Users.ID = Registrations.Timestamp.UserID AND
  Registrations.Date >= '2020-02-27'
ORDER BY
  Users.ID,
  Registrations.Timestamp;

这种问题可能不是唯一的,但我无法通过搜索一些类似的问题来找出解决方案。

2 个答案:

答案 0 :(得分:1)

首先使用row_number(),然后进行过滤。也可以用来学习正确的,明确的,标准,可读的JOIN语法:

Select u.*, r.*,
       (case when seqnum % 2 = 1  then 'entry' else 'departure' end) as type
FROM users u JOIN
     (SELECT r.*,
             ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY Date) as seqnum
      FROM Registrations r
     ) r
     ON u.ID = r.Timestamp.UserID
WHERE r.Date >= '2020-02-27'
ORDER BY u.ID, r.Timestamp;

答案 1 :(得分:0)

为什么不添加按时间戳排序的等级/行号,而是使用这些值来确定出发和进入的地方

Select *, case when row_num % 2 = 0  then 'departure' else 'entry' end as type
FROM
(SELECT
    Users.ID,
     row_number() over (partition by ID order by timestamp) as row_num
        FROM
          Users,
          Registrations
        WHERE
          Users.ID = Registrations.Timestamp.UserID AND
          Registrations.Date >= '2020-02-27'
        ORDER BY
          Users.ID,
          Registrations.Timestamp) a;