如何使用SQL活动范围生成给定的事件日期?

如何使用SQL活动范围生成给定的事件日期?,sql,select,Sql,Select,我有以下格式的表格: | user_name | date | number_of_visits | | cat005 | 2015-06-03 | 5 | | cat005 | 2015-06-08 | 1 | | dog009 | 2015-06-01 | 7 | | dog009 | 2015-06-19 | 2 | 因此,对于每个用

我有以下格式的表格:

| user_name | date       | number_of_visits |
| cat005    | 2015-06-03 |      5           |
| cat005    | 2015-06-08 |      1           |
| dog009    | 2015-06-01 |      7           |
| dog009    | 2015-06-19 |      2           |
因此,对于每个用户,我都有给定日期的访问次数。如果给定用户在给定日期没有访问,则数据库中没有记录(换句话说,如果访问次数等于零,我们不
保存访问次数)

现在我想用这个表生成另一个表,其中每个用户都有活动范围。在这里,我们使用了以下“活跃”的定义:如果用户在过去10天内至少进行了一次访问,则该用户在给定的一天被视为“活跃”。所以,我想要这样的东西:

| user_name | active_start | active_end |
| cat005    | 2015-03-02   | 2015-03-25 |    
| cat005    | 2015-03-29   | 2015-06-01 |
| dog009    | 2015-04-01   | 2015-06-01 |
请注意,两个示例中的数据不一致。根据使用的定义,
active\u end
是独占的(这意味着用户在此日期没有访问)。例如,上表中的第一行表示用户在
2015-03-02
时处于活动状态(他/她至少进行了一次访问)。也可以说,在
2015-03-01
(前一天),该用户没有活动,这意味着他/她超过10天没有访问。也可以说,在
2015-03-25
use没有访问,这是第11天没有访问(因此,用户被系统“切换”到非活动状态)


如何使用SQL生成第二个表。

这有点棘手。一种方法是确定活动周期的起始位置。然后使用前几天活动的累计总和。此累积和提供了一个聚合标准

以下列出了活动天数:

select t.*,
       (select t.*,
               (case when date > lag(date) over (partition by user_name order by date) + 10 -- date arithmetic varies by database
                     then 1
                     else 0
                end) as StartPeriodFlag
from table t;
然后,累积总和提供分组所需的信息:

with t as (
      select t.*,
             (select t.*,
                     (case when date > lag(date) over (partition by user_name order by date) + 10 -- date arithmetic varies by database
                           then 1
                           else 0
                      end) as StartPeriodFlag
      from table t
     )
select user_name, min(date) as startdate,
       max(date) + 10 as enddate
from (select t.*,
             sum(StartPeriodFlag) over (partition by user_name order by date) as grp
      from t
     ) t
group by user_name, grp;
如上所述,日期算法因数据库而异。这使用了简单的
+10
,但确切的功能可能因数据库而异。

Oracle 11g R2架构设置

CREATE TABLE ACTIVITY ( user_name, "date", number_of_visits ) AS
          SELECT 'cat005', DATE'2015-06-03', 5 FROM DUAL
UNION ALL SELECT 'cat005', DATE'2015-06-08', 1 FROM DUAL
UNION ALL SELECT 'dog009', DATE'2015-06-01', 7 FROM DUAL
UNION ALL SELECT 'dog009', DATE'2015-06-19', 2 FROM DUAL
WITH changes AS (
  SELECT user_name,
         "date",
         CASE WHEN "date" <= LAG( "date" ) OVER ( PARTITION BY user_name ORDER BY "date" ) + INTERVAL '10' DAY
              THEN 0
              ELSE 1 END AS change_group
  FROM   ACTIVITY
),
groups AS (
  SELECT user_name,
         "date",
         SUM( change_group ) OVER ( PARTITION BY user_name ORDER BY "date" ) AS grp
  FROM   changes
)
SELECT  user_name,
        MIN( "date" ) AS activity_start,
        MAX( "date" ) + INTERVAL '10' DAY AS activity_end
FROM    groups
GROUP BY
        USER_NAME,
        GRP
| USER_NAME |         ACTIVITY_START |           ACTIVITY_END |
|-----------|------------------------|------------------------|
|    dog009 | June, 19 2015 00:00:00 | June, 29 2015 00:00:00 |
|    dog009 | June, 01 2015 00:00:00 | June, 11 2015 00:00:00 |
|    cat005 | June, 03 2015 00:00:00 | June, 18 2015 00:00:00 |
WITH changes AS (
  SELECT user_name,
         "date",
         CASE WHEN "date" <= LAG( "date" ) OVER ( PARTITION BY user_name ORDER BY "date" ) + INTERVAL '10' DAY
              THEN null
              ELSE "date" END AS first_date,
         CASE WHEN "date" >= LEAD( "date" ) OVER ( PARTITION BY user_name ORDER BY "date" ) - INTERVAL '10' DAY
              THEN null
              ELSE "date" + INTERVAL '10' DAY END AS last_date
  FROM   ACTIVITY
)
SELECT DISTINCT
       user_name,
       LAST_VALUE(  first_date ) IGNORE NULLS OVER ( PARTITION BY user_name ORDER BY "date" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS activity_start,
       FIRST_VALUE( last_date  ) IGNORE NULLS OVER ( PARTITION BY user_name ORDER BY "date" ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) AS activity_end
FROM   changes
| USER_NAME |         ACTIVITY_START |           ACTIVITY_END |
|-----------|------------------------|------------------------|
|    cat005 | June, 03 2015 00:00:00 | June, 18 2015 00:00:00 |
|    dog009 | June, 01 2015 00:00:00 | June, 11 2015 00:00:00 |
|    dog009 | June, 19 2015 00:00:00 | June, 29 2015 00:00:00 |
查询1

CREATE TABLE ACTIVITY ( user_name, "date", number_of_visits ) AS
          SELECT 'cat005', DATE'2015-06-03', 5 FROM DUAL
UNION ALL SELECT 'cat005', DATE'2015-06-08', 1 FROM DUAL
UNION ALL SELECT 'dog009', DATE'2015-06-01', 7 FROM DUAL
UNION ALL SELECT 'dog009', DATE'2015-06-19', 2 FROM DUAL
WITH changes AS (
  SELECT user_name,
         "date",
         CASE WHEN "date" <= LAG( "date" ) OVER ( PARTITION BY user_name ORDER BY "date" ) + INTERVAL '10' DAY
              THEN 0
              ELSE 1 END AS change_group
  FROM   ACTIVITY
),
groups AS (
  SELECT user_name,
         "date",
         SUM( change_group ) OVER ( PARTITION BY user_name ORDER BY "date" ) AS grp
  FROM   changes
)
SELECT  user_name,
        MIN( "date" ) AS activity_start,
        MAX( "date" ) + INTERVAL '10' DAY AS activity_end
FROM    groups
GROUP BY
        USER_NAME,
        GRP
| USER_NAME |         ACTIVITY_START |           ACTIVITY_END |
|-----------|------------------------|------------------------|
|    dog009 | June, 19 2015 00:00:00 | June, 29 2015 00:00:00 |
|    dog009 | June, 01 2015 00:00:00 | June, 11 2015 00:00:00 |
|    cat005 | June, 03 2015 00:00:00 | June, 18 2015 00:00:00 |
WITH changes AS (
  SELECT user_name,
         "date",
         CASE WHEN "date" <= LAG( "date" ) OVER ( PARTITION BY user_name ORDER BY "date" ) + INTERVAL '10' DAY
              THEN null
              ELSE "date" END AS first_date,
         CASE WHEN "date" >= LEAD( "date" ) OVER ( PARTITION BY user_name ORDER BY "date" ) - INTERVAL '10' DAY
              THEN null
              ELSE "date" + INTERVAL '10' DAY END AS last_date
  FROM   ACTIVITY
)
SELECT DISTINCT
       user_name,
       LAST_VALUE(  first_date ) IGNORE NULLS OVER ( PARTITION BY user_name ORDER BY "date" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS activity_start,
       FIRST_VALUE( last_date  ) IGNORE NULLS OVER ( PARTITION BY user_name ORDER BY "date" ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) AS activity_end
FROM   changes
| USER_NAME |         ACTIVITY_START |           ACTIVITY_END |
|-----------|------------------------|------------------------|
|    cat005 | June, 03 2015 00:00:00 | June, 18 2015 00:00:00 |
|    dog009 | June, 01 2015 00:00:00 | June, 11 2015 00:00:00 |
|    dog009 | June, 19 2015 00:00:00 | June, 29 2015 00:00:00 |
查询2

CREATE TABLE ACTIVITY ( user_name, "date", number_of_visits ) AS
          SELECT 'cat005', DATE'2015-06-03', 5 FROM DUAL
UNION ALL SELECT 'cat005', DATE'2015-06-08', 1 FROM DUAL
UNION ALL SELECT 'dog009', DATE'2015-06-01', 7 FROM DUAL
UNION ALL SELECT 'dog009', DATE'2015-06-19', 2 FROM DUAL
WITH changes AS (
  SELECT user_name,
         "date",
         CASE WHEN "date" <= LAG( "date" ) OVER ( PARTITION BY user_name ORDER BY "date" ) + INTERVAL '10' DAY
              THEN 0
              ELSE 1 END AS change_group
  FROM   ACTIVITY
),
groups AS (
  SELECT user_name,
         "date",
         SUM( change_group ) OVER ( PARTITION BY user_name ORDER BY "date" ) AS grp
  FROM   changes
)
SELECT  user_name,
        MIN( "date" ) AS activity_start,
        MAX( "date" ) + INTERVAL '10' DAY AS activity_end
FROM    groups
GROUP BY
        USER_NAME,
        GRP
| USER_NAME |         ACTIVITY_START |           ACTIVITY_END |
|-----------|------------------------|------------------------|
|    dog009 | June, 19 2015 00:00:00 | June, 29 2015 00:00:00 |
|    dog009 | June, 01 2015 00:00:00 | June, 11 2015 00:00:00 |
|    cat005 | June, 03 2015 00:00:00 | June, 18 2015 00:00:00 |
WITH changes AS (
  SELECT user_name,
         "date",
         CASE WHEN "date" <= LAG( "date" ) OVER ( PARTITION BY user_name ORDER BY "date" ) + INTERVAL '10' DAY
              THEN null
              ELSE "date" END AS first_date,
         CASE WHEN "date" >= LEAD( "date" ) OVER ( PARTITION BY user_name ORDER BY "date" ) - INTERVAL '10' DAY
              THEN null
              ELSE "date" + INTERVAL '10' DAY END AS last_date
  FROM   ACTIVITY
)
SELECT DISTINCT
       user_name,
       LAST_VALUE(  first_date ) IGNORE NULLS OVER ( PARTITION BY user_name ORDER BY "date" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS activity_start,
       FIRST_VALUE( last_date  ) IGNORE NULLS OVER ( PARTITION BY user_name ORDER BY "date" ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) AS activity_end
FROM   changes
| USER_NAME |         ACTIVITY_START |           ACTIVITY_END |
|-----------|------------------------|------------------------|
|    cat005 | June, 03 2015 00:00:00 | June, 18 2015 00:00:00 |
|    dog009 | June, 01 2015 00:00:00 | June, 11 2015 00:00:00 |
|    dog009 | June, 19 2015 00:00:00 | June, 29 2015 00:00:00 |

请用您正在使用的数据库标记您的问题?你想要的结果与样本数据不符。你应该解决这个问题。