六个月内保留的参与者百分比

时间:2013-07-29 20:30:41

标签: sql sql-server date date-range

我是MS SQL服务器的新手。每个人都建议尝试这个网站。开始!

我正在尝试编写查询,以测试参与学术计划的不同类型的结果指标。有几种不同的方法来计算我想尝试的结果测量。我想要计算的结果是:在六个月的课程中保留的参与者的百分比是多少?我正在测试不同的方式来定义参与者和不同的时间范围。我正在尝试生成4个查询。不幸的是,我必须使用不同的表:出勤,状态,退出,无效。我已经在下面列出了每个样本数据

查询

  1. 参与者被定义为每个人每周至少两次上课,为期6个月(总共181天),从2012年7月1日开始到2013年6月30日结束,因此是会计年度的长度。如果参与者退出无效会被删除。
  2. 参与者被定义为从2013年1月1日开始,每周至少两次上课,为期6个月(总共181天)。如果参与者退出或变为不活动他们被放弃了。
  3. 参与者被定义为从2013年1月1日至今,每周至少两次上课的人
  4. 参与者被定义为学生的注册开始日期,直到他们退出或变为非活动状态。
  5. 参与者(分子)参与者/所有服务的学生(分母)

    我正在寻找的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')
    

2 个答案:

答案 0 :(得分:1)

给这些镜头(改变因为我错过了很大一部分问题)

    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);

和一个帮助你的平方小人:http://sqlfiddle.com/#!6/97230/3 祝你好运!

答案 1 :(得分:1)

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

虽然我试图解决它,但我在Niels van der Rest - Finding continuous ranges in a set of numbers找到了绝对精彩的答案。因此,我将为您提供第1部分的一般查询,您可以更改参数并获取第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部分对我来说似乎有点不清楚,你能澄清一下吗?