2013-07-29 11 views
7

Ich bin ein Schullehrer sehr neu zu MS SQL Server. Jeder schlägt vor, diese Seite auszuprobieren. Hier geht!% der Teilnehmer, die während sechs Monaten beibehalten werden

Ich versuche, Abfragen zu schreiben, um verschiedene Arten von Ergebnismaßen für die Teilnahme an einem akademischen Programm zu testen. Es gibt verschiedene Möglichkeiten, diese Ergebnismessung zu berechnen, die ich ausprobieren möchte. Das Ergebnis, das ich zu berechnen versuche, ist: Wie hoch ist der Prozentsatz der Teilnehmer, die während sechs Monaten des Programms erhalten bleiben? Ich teste verschiedene Möglichkeiten, Teilnehmer und verschiedene Zeitbereiche zu definieren. Es gibt 4 Abfragen, die ich erstellen möchte. Leider muss ich für verschiedene Tabellen verwenden: Teilnahme, Status, Deenrolled, Inaktiv. Ich habe von jedem enthaltenen Beispieldaten unter

Abfragen

  1. Ein Teilnehmer wird als jeder definiert, die eine Klasse mindestens zweimal in der Woche für 6 Monate besucht (181 Tage insgesamt) am 1. Juli 2012 beginnen und Ende Juni 30. 2013, so die Länge des Geschäftsjahres.Wenn ein Teilnehmer ist deenrolled oder inaktiv sie fallen gelassen werden.
  2. Ein Teilnehmer wird als jeder definiert, die eine Klasse mindestens zweimal in der Woche für 6 Monate (181 Tage insgesamt) ab 1. Januar 2013 besuchte Wenn ein Teilnehmer ist deenrolled oder wird inaktiv sie fallen gelassen werden.
  3. ist ein Teilnehmer als jeder definiert, die 2013 bis
  4. heute am 1. Januar beginnt eine Klasse mindestens zweimal in der Woche besucht
  5. Ein Teilnehmer als Einschreibung Startdatum des Schülers definiert ist, bis sie deenrolled oder inaktiv.

Teilnehmer (Numerator) Teilnehmer/alle Studenten, die serviert wurden (Denominator)

Die 4 Abfrage Ausgänge ich suche sind verschiedene Versionen dieses:

Beispiel

Participants Served Percent_Served 
75    100  75%  

Ich habe mit verschiedenen Versionen der Abfrage unter

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 

und

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 

Jede Programmierung Unterstützung für diese Abfragen wird sehr geschätzt.

Im Folgenden finden Sie die Beispiel-/Beispieldatensätze.

Attendence_Date ist das Datum, an dem ein Student an einer Klasse teilgenommen hat.

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

Hier ist das Registrierungsdatum enthalten.

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

Hier ist das Datum der Abmeldung.

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

und inaktive

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

Willkommen, ein paar Tipps: Die Leute wollen sehen, was Sie bisher versucht haben, was nicht funktioniert (Fehler die Sie erhalten oder Beispielausgabe, die nicht wie gewünscht ist). Sample gewünschte Ausgabe ist auch hilfreich, da es oft einfacher ist, Daten zu verstehen als Beschreibung der Daten. Sie können auch SQL Fiddle, um Ihren Probentisch (e) verwenden, für die Menschen zu fragen: http://sqlfiddle.com/#!3 –

+0

@steoleary Ich bin sehr neu, so, damit ich für Beispiele gesucht online. Ich habe nur etwas Code hinzugefügt, den ich versucht habe zusammen zu stellen. – Matty34

+0

@goatco danke. Ich werde es mir ansehen. Ich bin sehr neu und ich habe viele online gesehen. – Matty34

Antwort

1

Nun soll ich sagen, dass nicht leicht ist. Das Hauptproblem bestand darin, "mindestens zweimal pro Woche für einen sechsten Monat zu lösen" - es ist leicht, zweimal pro Woche zu kalkulieren, aber es sollten 6 kontinuierliche Monate sein! Finding continuous ranges in a set of numbers-

Während ich habe versucht, es zu lösen, habe ich absolut brillant Antwort von Niels van der Rest gefunden. Also werde ich Ihnen allgemeine Abfrage geben für die Teil 1, können Sie die Parameter ändern und für Part Ergebnis erhalten 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 

ich SQL FIDDLE EXAMPLE erstellt haben, können Sie die Abfrage testen.

Teil 3 ist einfach

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 

Teil 4 für mich etwas unklar erscheint, könnte man klären?

1

Geben Sie diese ein Schuss (geändert, weil ich einen großen Teil der Frage verpasst)

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

und eine sqlfiddle um Ihnen zu helfen: http://sqlfiddle.com/#!6/97230/3 Gut Glück!

+0

Was ist mindestens zweimal pro Woche für einen sechsten Monat Zustand? –

+0

@Roman - Die zweite Abfrage wird dabei, dass seit der OP hatte ein Startdatum 1.1.2013 für diesen Fall. Ich habe gerade Mathe gemacht, um am 30.06.2013 als 6 Monate heraus zu kommen. Sie könnten '06/30/2013' mit DATEADD (Monat, 6, '01/01/2013) ersetzen, aber warum die Abfrage machen die Mathematik, wenn es immer eine Konstante sein wird. –

+0

gut, korrigieren Sie mich, wenn ich falsch liege, aber mindestens zweimal pro Woche für ein sechstes Jahr bedeutet jede Woche des sechsten Monats? AFAIK, wird Ihre Abfrage ID zurückgeben, auch wenn er/sie nur eine Woche mehr als einmal besucht? –

Verwandte Themen