六个月期间保持参与的参与者百分比

7

我是一名学校教师,对MS SQL服务器非常新。每个人都建议我试试这个网站。就开始吧!

我正在尝试编写查询来测试不同类型的参与学术计划的结果措施。有几种不同的方法可以计算这个结果测量值,我想尝试一下。我正在尝试计算的结果是:在项目六个月期间保留参与者的百分比是多少? 我正在测试不同的参与者定义和不同的时间范围。我要生成4个查询。不幸的是,我必须使用4个不同的表格:Attendance, Status, Deenrolled, Inactive。我已经在下面包含了每个表格的样本数据。

查询

  1. 参与者被定义为在2012年7月1日至2013年6月30日这个财政年度内每周至少上两次课程的所有人,共181天。如果参与者被退学失活,则会被删除。
  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')

8
欢迎,几个提示:人们喜欢看到你已经尝试了什么,哪些部分不起作用(你收到的错误或样本输出与期望输出不一致)。提供样本期望输出也很有帮助,因为通常比数据描述更容易理解数据。你还可以使用SQL Fiddle来设置样本表格供人们查询:http://sqlfiddle.com/#!3 - Hart CO
@steoleary 我非常新手,所以一直在网上寻找示例。我刚刚添加了一些我一直在尝试拼凑的代码。 - Matty34
@goatco 谢谢。我会去看看的。我很新,一直在网上找很多例子。 - Matty34
1
这个问题需要一个更好的标题,一个反映编程问题而不是问题领域的标题。 - user47589
你使用的 SQL Server 版本是哪个? - Roman Pekar
2个回答

1

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

当我试图解决这个问题时,我发现了Niels van der Rest的绝妙答案 - 在一组数字中找到连续的范围。因此,我将为第一部分提供通用查询,您可以更改参数并获取第二部分的结果:

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,你可以测试查询。 第三部分很容易。
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

第四部分对我来说有点不清楚,你能解释一下吗?

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

and an sqlfiddle to help you out: http://sqlfiddle.com/#!6/97230/3 祝你好运!

每周至少两次,持续六个月怎么样? - Roman Pekar
@Roman - 第二个查询是因为 OP 对于该案例有一个开始日期为 2013 年 1 月 1 日。我只是做了数学计算,得出了 2013 年 6 月 30 日为 6 个月后的日期。你可以用 DATEADD(MONTH, 6,'01/01/2013') 替换 '06/30/2013',但为什么要让查询进行数学计算,当它总是一个常量呢? - Barbara Laird
请纠正我如果我错了,但是每周至少两次六个月意味着六个月的每一周?据我所知,您的查询将返回ID,即使他/她只参加了一周超过一次? - Roman Pekar
看一下我的答案 :) - Roman Pekar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接