【问题标题】:% of participants that are retained during six months在六个月内保留的参与者的百分比
【发布时间】:2013-07-29 19:24:40
【问题描述】:

我是一名对 MS SQL 服务器非常陌生的学校老师。每个人都建议尝试这个网站。开始!

我正在尝试编写查询来测试参与学术计划的不同类型的结果度量。我想尝试几种不同的方法来计算这种结果测量。我试图计算的结果是:在六个月的计划中保留的参与者百分比是多少?我正在测试定义参与者和不同时间范围的不同方法。我正在尝试生成 4 个查询。不幸的是,我必须使用不同的表:出勤、状态、取消注册、非活动。我已经包含了来自以下每个的示例数据

查询

  1. 参与者定义为从 2012 年 7 月 1 日到 2013 年 6 月 30 日,每周至少参加两次课程并持续 6 个月(共 181 天)的每个人,因此会计年度的长度。如果参与者是 deenrolled 或 inactive 它们将被丢弃。
  2. 参与者的定义是从 2013 年 1 月 1 日开始,每周至少参加两次课程并持续 6 个月(共 181 天)的所有人。如果参与者取消注册或变为非活动状态 他们被丢弃了。
  3. 参与者的定义是从 2013 年 1 月 1 日到今天,每周至少参加两次课程的所有人
  4. 参与者被定义为学生的注册开始日期,直到他们被取消注册或变为非活动状态。

参与者(分子)参与者/所有被服务的学生(分母)

我正在寻找的 4 个查询输出是这个的不同版本:

例子

Participants    Served   Percent_Served
75               100        75%      

我一直在搞乱下面的不同版本的查询

 SELECT 
Count (distinct ID) as Count, 
  Count  ( DATEADD( dd, -181, DATEADD(wk, DATEDIFF(wk,0,Date), 0)) > 2 as Participants ,
FROM Attendance
where Attendence_date date between '07/01/2012' and '06/30/2013'
and ID not in (Select ID from Inactive) 
or ID not in (select ID from Deenrolled) 
GROUP BY ID

 SELECT 
Count (distinct ID) as Count, 
  Count  ( DATEADD( dd, -181, DATEADD(wk, DATEDIFF(wk,0,Date), 0)) - Enrolled_Date  as Participants ,
FROM Attendance
where Attendence_date date between '07/01/2012' and '06/30/2013'
and ID not in (Select ID from Inactive) 
or ID not in (select ID from Deenrolled) 
GROUP BY ID

非常感谢您对这些查询的任何编程帮助。

以下是示例/示例数据集。

Attendence_date 是学生参加一节课的日期。

CREATE TABLE Attendance (
    ID int,
    Attendence_date datetime
    )

INSERT INTO Attendance VALUES 
(4504498,  '7/1/2012'),
(4504498,  '7/2/2012'),
(4504498,   '7/3/2012'),
(4504498,   '7/4/2012'),
(4504498,   '7/5/2012'),
(4504498,   '7/8/2012'),
(4504498,   '7/9/2012'),
(4504498,   '7/10/2012'),
(4504498,   '7/11/2012'),
(4504498,   '7/12/2012'),
(4504498,   '7/1/2012'),
(4504498,   '7/2/2012'),
(4504498,   '7/3/2012'),
(4504498,   '7/4/2012'),
(4504498,   '7/5/2012'),
(4504498,   '7/8/2012'),
(4504498,   '7/9/2012'),
(4504498,   '7/10/2012'),
(4504498,   '7/11/2012'),
(4504498,   '7/12/2012'),
(9201052,   '7/15/2012'),
(9201052,   '7/16/2012'),
(9201052,   '7/17/2012'),
(9201052,   '7/17/2012'),
(9201052,   '7/18/2012'),   
(7949745,   '7/17/2012'),   
(7949745,   '7/18/2012'),
(7949745,   '7/23/2012'),   
(7949745,   '7/23/2012'),   
(7949745,   '7/24/2012'),
(7949745,   '7/26/2012'),
(7949745,   '7/26/2012'),   
(7949745,   '8/8/2012'),    
(7949745,   '8/8/2012'),    
(7949745,   '11/5/2012'),   
(7949745,   '11/5/2012'),   
(7949745,   '11/5/2012'),   
(7949745,   '11/6/2012'),   
(7949745,   '11/6/2012'),   
(7949745,   '11/6/2012'),   
(7949745,   '11/7/2012'),   
(7949745,   '11/7/2012'),   
(7949745,   '11/7/2012')

这里是包含注册日期。

CREATE TABLE [Status] (
    ID int,
    Intake_Date datetime ,
   Engaged_Date datetime ,
   Enrolled_Date datetime)
INSERT INTO [Status] VALUES 
(7949745, '3/7/2012',   '7/17/2012', '3/8/2012'),
(4504498, '2/21/2013',  '3/5/2013',  '3/22/2013'),
(1486279, '4/18/2013',  '5/7/2013',   '5/20/2013'),
(9201052, '5/15/2012',  '7/13/2012',  '5/15/2012'),
(1722390, '3/5/2012',   '8/27/2012', '3/8/2012'),
(7735695, '9/7/2012',   '9/7/2012',  '9/28/2012'),
(9261549, '3/7/2012',   '7/24/2012', '3/8/2012'),
(3857008, '3/15/2013',  '3/18/2013', '4/3/2013'),
(8502583, '3/14/2013',     '4/15/2013', '5/3/2013'),
(1209774,  '4/19/2012',  '1/1/2012',   '4/24/2012') 

这里包含取消注册日期。

CREATE TABLE Deenrolled (
    ID int,
    Deenrolled_Date datetime)
INSERT INTO Deenrolled  VALUES 
(7949745,    '2/4/2013'),
(5485272,    '07/08/2013'),
(8955628,    '01/10/2013'),
(5123221,    '7/8/2013'),
(5774753,    '7/18/2013'),
(3005451,    '2/18/2013'),
(7518818,    '05/29/2013'),
(9656985,    '6/20/2013'),
(2438101,    '7/17/2013'),
(1437052,    '7/25/2013'),
(9133874,    '4/25/2013'),
(7007375,    '6/19/2013'),
(3178181,    '5/24/2013')

并且不活跃

CREATE TABLE Inactive (
    ID int,
   Effect_Date datetime)
INSERT INTO Inactive VALUES 
(1209774,       '10/12/2012'),
(5419494,       '10/12/2012'),
(4853049,       '10/9/2012'),
(1453678,       '5/23/2013'),
(1111554,       '7/16/2012'),
(5564128,       '2/15/2013'),
(1769234,       '7/16/2012')

【问题讨论】:

  • 欢迎,一些提示:人们喜欢查看您迄今为止尝试过的内容、无效的内容(您收到的错误或与您不希望的示例输出)。示例所需的输出也很有帮助,因为它通常比数据描述更容易理解数据。您还可以使用 SQL Fiddle 设置示例表以供人们查询:sqlfiddle.com/#!3
  • @steoleary 我是新手,所以一直在网上找例子。我刚刚添加了一些我一直试图拼凑起来的代码。
  • @goatco 谢谢。我会看看。我很新,我一直在网上寻找很多例子。
  • 这个问题需要一个更好的标题,一个反映编程问题,而不是问题域的标题。
  • 您使用哪个版本的 SQL Server?

标签: sql sql-server date date-range


【解决方案1】:

好吧,我应该说这不是一件容易的事。主要问题是解决“六个月至少每周两次”部分 - 每周计算两次很容易,但应该是连续 6 个月!

虽然我试图解决它,但我找到了 Niels van der Rest - Finding continuous ranges in a set of numbers 的绝妙答案。所以我给你Part 1的一般查询,你可以更改参数并获得Part 2的结果:

declare @Weeks int, @PerWeek int, @StartDate date, @EndDate date, @count

select
    @StartDate = '20120701',
    @EndDate = '20130630',
    @Weeks = 26, -- 6 month or 26 weeks
    @PerWeek = 2 -- twice per week

select @count = count(distinct A.ID)
from Attendance as A
where
    A.Attendence_date between @StartDate and @EndDate and
    A.ID not in (select T.ID from Deenrolled as T) and
    A.ID not in (select T.ID from Inactive as T)

;with CTE as (
    -- Week numbers, filter by dates
    select
        A.ID,
        datediff(dd, @StartDate, A.Attendence_date) / 7 as Wk
    from Attendance as A
    where
        A.Attendence_date between @StartDate and @EndDate and
        A.ID not in (select T.ID from Deenrolled as T) and
        A.ID not in (select T.ID from Inactive as T)
  ), CTE2 as (
    -- Group by week, filter less then @PerWeek per week, calculate row number
    select
        Wk, ID,
        row_number() over (partition by ID order by Wk) as Row_Num
    from CTE
    group by Wk, ID
    having count(*) >= @PerWeek
)
-- Final query - group by difference between week and row_number
select 100 * cast(count(distinct ID) as float) / @count
from CTE2
group by ID, Wk - Row_Num
having count(*) >= @Weeks

我已经创建了SQL FIDDLE EXAMPLE,你可以测试查询。

第 3 部分很简单

declare @PerWeek int, @StartDate date

select
    @StartDate = '20130101',
    @PerWeek = 2 -- twice per week

select @count = count(distinct A.ID)
from Attendance as A
where
    A.Attendence_date >= @StartDate and
    A.ID not in (select T.ID from Deenrolled as T) and
    A.ID not in (select T.ID from Inactive as T)

;with CTE as (
    -- Week numbers, filter by dates
    select
        A.ID,
        datediff(dd, @StartDate, A.Attendence_date) / 7 as Wk
    from Attendance as A
    where
        A.Attendence_date >= @StartDate and
        A.ID not in (select T.ID from Deenrolled as T) and
        A.ID not in (select T.ID from Inactive as T)
  ), CTE2 as (
    -- Group by week, filter less then @PerWeek per week
    select distinct ID
    from CTE
    group by Wk, ID
    having count(*) >= @PerWeek
)
select 100 * cast(count(*) as float) / @count from CTE2

第 4 部分对我来说似乎有点不清楚,你能澄清一下吗?

【讨论】:

    【解决方案2】:

    试一试(因为我错过了大部分问题而改变)

        SELECT  B.ID FROM
    (SELECT number
          FROM master.dbo.spt_values
          WHERE TYPE = 'P' AND number < datediff(week, '07/01/2012', '06/30/2013') ) AS W
        JOIN
    (SELECT A.ID, weeknum
      FROM
        (SELECT ID,  datediff(week, '07/01/2012',Attendence_date) AS weeknum
          FROM Attendance
          WHERE Attendence_date  BETWEEN '07/01/2012' AND '06/30/2013'
            AND ID NOT IN (SELECT ID FROM Deenrolled)
            AND ID NOT IN (SELECT ID FROM Inactive)) AS A
      GROUP BY A.ID, A.weeknum
      HAVING COUNT(A.ID) > 2) AS B ON W.number = B.weeknum
    GROUP BY B.ID
    HAVING COUNT(W.number) = datediff(week, '07/01/2012', '06/30/2013');
    
    SELECT  B.ID FROM
    (SELECT number
          FROM master.dbo.spt_values
          WHERE TYPE = 'P' AND number < datediff(week, '01/01/2013', '06/30/2013') ) AS W
        JOIN
    (SELECT A.ID, weeknum
      FROM
        (SELECT ID,  datediff(week, '01/01/2013',Attendence_date) AS weeknum
          FROM Attendance
          WHERE Attendence_date  BETWEEN '01/01/2013' AND '06/30/2013'
            AND ID NOT IN (SELECT ID FROM Deenrolled)
            AND ID NOT IN (SELECT ID FROM Inactive)) AS A
      GROUP BY A.ID, A.weeknum
      HAVING COUNT(A.ID) > 2) AS B ON W.number = B.weeknum
    GROUP BY B.ID
    HAVING COUNT(W.number) = datediff(week, '07/01/2012', '06/30/2013');
    
    SELECT  B.ID FROM
    (SELECT number
          FROM master.dbo.spt_values
          WHERE TYPE = 'P' AND number < datediff(week, '01/01/2013', '06/30/2013') ) AS W
        JOIN
    (SELECT A.ID, weeknum
      FROM
        (SELECT ID,  datediff(week, '01/01/2013',GetDate()) AS weeknum
          FROM Attendance
          WHERE Attendence_date  BETWEEN '01/01/2013' AND GetDate()
            AND ID NOT IN (SELECT ID FROM Deenrolled)
            AND ID NOT IN (SELECT ID FROM Inactive)) AS A
      GROUP BY A.ID, A.weeknum
      HAVING COUNT(A.ID) > 2) AS B ON W.number = B.weeknum
    GROUP BY B.ID
    HAVING COUNT(W.number) = datediff(week, '07/01/2012', GetDate());
    
    SELECT DISTINCT(Attendance.ID)
      FROM Attendance
      WHERE Attendance.ID NOT IN (SELECT ID FROM Deenrolled)
          AND ID NOT IN (SELECT ID FROM Inactive);
    

    还有一个 sqlfiddle 可以帮助你:http://sqlfiddle.com/#!6/97230/3 祝你好运!

    【讨论】:

    • 在第六个月的情况下每周至少两次怎么样?
    • @Roman - 第二个查询正在执行此操作,因为 OP 的开始日期为 2013 年 1 月 1 日。我只是做了数学计算,得出 2013 年 6 月 30 日为 6 个月。您可以将 '06/30/2013' 替换为 DATEADD(MONTH, 6,'01/01/2013'),但是当查询始终是一个常量时,为什么还要进行数学运算呢。
    • 好吧,如果我错了,请纠正我,但是第六个月每周至少两次意味着第六个月的每周? AFAIK,即使他/她只参加一周以上一次,您的查询也会返回 ID?
    • 看看我的回答:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-02
    • 2020-03-10
    • 1970-01-01
    相关资源
    最近更新 更多