Sql 获取登录站点的连续30天用户数

Sql 获取登录站点的连续30天用户数,sql,oracle,Sql,Oracle,我有一个登录到我的网站的表格,格式如下: logins +---------+--------------------------+-----------------------+ | USER_ID | LOGIN_TIMESTAMP | LOGOUT_TIMESTAMP | +---------+--------------------------+-----------------------+ | 274385 | 01-JAN-20 02.56.12 PM

我有一个登录到我的网站的表格,格式如下:

logins
+---------+--------------------------+-----------------------+
| USER_ID |     LOGIN_TIMESTAMP      |   LOGOUT_TIMESTAMP    |
+---------+--------------------------+-----------------------+
|  274385 | 01-JAN-20 02.56.12 PM    | 02-JAN-20 10.04.40 AM |
|   32498 | 01-JAN-20 05.12.14 PM    | 01-JAN-20 08.26.43 PM |
|  981231 | 01-JAN-20 04.41.04 PM    | 01-JAN-20 10.51.11 PM |
+---------+--------------------------+-----------------------+
我想计算一个在过去30天内每天只登录一次的用户的唯一计数,以获得如下信息 注意-USER_COUNT_LAST_30_DAYS仅统计在前30天内仅登录一次的用户 :

我的第一个想法是如下所示的查询,但我认识到这只是统计过去30天内登录的所有用户,而不是只登录一次的用户

SELECT 
  CAST(LOGIN_TIMESTAMP AS DATE),
  COUNT(DISTINCT USER_ID) 
FROM 
  logins 
WHERE 
  LOGIN_TIMESTAMP > SYSDATE - 30 
GROUP BY
  CAST(LOGIN_TIMESTAMP AS DATE);

这个查询是否可以帮助我统计在过去30天内使用rownum分区过滤器在用户id上只登录一次的用户数?或者我需要确保获得滚动30天计数吗?

请使用下面的查询,因为日期中有字符串值PM,所以不能使用cast函数,而必须使用to_date并转换为日期格式

SELECT 
  to_date(LOGIN_TIMESTAMP, 'DD-MON-YYYY hh.mi.ss PM'),
  COUNT(DISTINCT USER_ID) 
FROM 
  logins 
WHERE 
LOGIN_TIMESTAMP >= SYSDATE - 30 
GROUP BY
to_date(LOGIN_TIMESTAMP, 'DD-MON-YYYY hh.mi.ss PM');

日期数据类型仍然有一个时间组件,即使格式掩码没有显示它。您可以在日期或时间戳上使用TRUNC函数。如果你真的想把你的一天限制在一天之内,你需要截断时间戳。您还需要使用INTERVAL,因为时间戳数学和日期数学不一样:

SELECT TRUNC(LOGIN_TIMESTAMP) LOGIN_DATE,
       COUNT(DISTINCT USER_ID) USER_COUNT
  FROM logins 
 WHERE TRUNC(LOGIN_TIMESTAMP) > TRUNC(SYSTIMESTAMP - INTERVAL '30' DAY)
 GROUP BY TRUNC(LOGIN_TIMESTAMP)
 ORDER BY TRUNC(LOGIN_TIMESTAMP) ASC;
例如:

alter session set nls_date_format='DD-MON-YY HH24.MI.SS';
SELECT
   SYSTIMESTAMP raw_timestamp,
   CAST(SYSTIMESTAMP AS DATE) raw_date,
   TRUNC(CAST(SYSTIMESTAMP AS DATE)) trunc_date,
   TRUNC(SYSTIMESTAMP) - INTERVAL '30' DAY
from dual;

RAW_TIMESTAMP                          RAW_DATE           TRUNC_DATE         TRUNC(SYSTIMESTAMP
-------------------------------------- ------------------ ------------------ ------------------
25-JUN-20 12.27.21.756299000 PM -04:00 25-JUN-20 12.27.21 25-JUN-20 00.00.00 26-MAY-20 00.00.00
要识别只登录过一次的用户,请尝试以下操作:

WITH user_logins as (
    SELECT USER_ID,
           COUNT(*) LOGIN_COUNT
      FROM logins 
     WHERE TRUNC(LOGIN_TIMESTAMP) > TRUNC(SYSTIMESTAMP - INTERVAL '30' DAY)
     GROUP BY USER_ID)
SELECT user_id, login_count 
  from user_logins 
 where login_count=1
 order by user_id;

AM/PM只是时间戳数据类型格式掩码的一部分。不需要显式地将其作为cast的一部分。AM.PM不符合oracle Sql标准。强制转换函数将不允许您转换它。选择演员“01-JAN-20 02.56.12 PM”作为双重日期;-此查询将失败。我认为登录时间戳是TIMESTAMP类型,而不是VARCHAR2,因为OP会与sysdate进行比较。@Jimmacauley感谢您的回答。您还可以建议如何修改计数以仅捕获在过去30天内登录过一次的用户吗?TRUNC使用时间戳,您不需要强制转换到最新状态。@pmdba感谢您的回答。您是否也可以建议如何修改计数以仅捕获在过去30天内登录一次的用户?我发现描述有点混乱。您想要查询中的每天不同用户的计数,还是问题中的前30天内仅登录一次的实际用户计数?您可能应该提供具有代表性的样本数据和相应的结果unambiguous@GMB谢谢你的评论。我想从我的问题中得到答案——在过去的30天里,只有一次登录的用户的实际数量。我想把这个问题描述为我的出发点,因为我不确定从那里该做什么。我曾考虑使用rownumber分区,但不知道如何修改它以使其在滚动的基础上工作。我更新了我原来的帖子来反映这一点。
WITH user_logins as (
    SELECT USER_ID,
           COUNT(*) LOGIN_COUNT
      FROM logins 
     WHERE TRUNC(LOGIN_TIMESTAMP) > TRUNC(SYSTIMESTAMP - INTERVAL '30' DAY)
     GROUP BY USER_ID)
SELECT user_id, login_count 
  from user_logins 
 where login_count=1
 order by user_id;