2013-07-29 4 views
7

Я учитель школы, очень новый для MS SQL-сервера. Все предлагают попробовать этот сайт. Вот оно!% участников, которые сохраняются в течение шести месяцев

Я пытаюсь написать запросы для тестирования различных типов результатов для участия в академической программе. Существует несколько различных способов расчета этого измерения результатов, которое я хотел бы попробовать. Результат, который я пытаюсь рассчитать: Какова% участников, которые сохраняются в течение шести месяцев после программы? Я тестирую различные способы определения участника и разных временных диапазонов. Есть 4 вопроса, которые я пытаюсь создать. К сожалению, я должен использовать для разных таблиц: Посещаемость, статус, деактивированный, неактивный. Я включил выборочные данные из каждого ниже

запросов

  1. Участник определяется как все, что присутствовал класс по крайней мере два раза в неделю в течение 6 месяцев (всего 181 дней), начиная с 1 июля 2012 года и до июня 30-го 2013 года, поэтому продолжительность финансового года. Если участник deenrolled или неактивный, они отбрасываются.
  2. Участник определяется как все, что присутствовал класс по крайней мере два раза в неделю в течение 6 месяцев (181 дней общего), начиная с 1 января 2013 г. Если участник deenrolled или становится неактивный они отбрасываются.
  3. Участник определяется как все, что присутствовал класс по крайней мере два раза в неделю не начиная с 1 января 2013 года до сегодняшнего дня
  4. Участник определяется как регистрации даты начала студента, пока они не deenrolled или становятся неактивными.

Участник (числитель) участник/все студенты, которые служили (знаменатель)

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 –

+0

@steoleary Я очень новый, поэтому я искал примеры в Интернете. Я просто добавил в какой-то код, который я пытался перечислить. – Matty34

+0

@goatco спасибо. Я это проверю. Я очень новый, и я искал много вариантов в Интернете. – Matty34

ответ

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 кажется немного неясным для меня, не могли бы вы уточнить?

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

и sqlfiddle, чтобы помочь вам: http://sqlfiddle.com/#!6/97230/3 Хороший удачи!

+0

Как минимум два раза в неделю ДЛЯ УСЛОВИЯ ШЕСТОГО МЕСЯЦА? –

+0

@Roman. Второй запрос делает это, поскольку в этом случае OP имела дату начала 1/1/2013. Я только что сделал математику, чтобы придумать 6/30/2013 как 6 месяцев. Вы можете заменить '06/30/2013 'на DATEADD (MONTH, 6, '01/01/2013), но зачем делать запрос математикой, когда она всегда будет постоянной. –

+0

хорошо, поправьте меня, если я ошибаюсь, но не реже двух раз в неделю на шестой месяц означает каждую неделю шестого месяца? AFAIK, ваш запрос вернет идентификатор, даже если он посещает только одну неделю более одного раза? –

Смежные вопросы