2009-10-23 10 views
7

Ho una tabella che registra l'id utente, il corso, il sessionid e il requestdate ogni volta che viene caricata una pagina web. Voglio calcolare la durata per userid per un determinato corsoid. È problematico farlo a causa di tempi di sovrapposizione.Query SQL per calcolare parte della durata della visita dalla tabella dei registri

I dati qui forniti dovrebbero comportare una durata di 10 minuti per utente per il corso 1. Non riesco a capire bene.

CREATE TABLE PageLogSample (
    id INT NOT NULL PRIMARY KEY IDENTITY 
, userid INT 
, courseid INT 
, sessionid INT 
, requestdate DATETIME 
); 

TRUNCATE TABLE PageLogSample; 

INSERT INTO PageLogSample (userid, courseid, sessionid, requestdate) 
-- [0, 10] = 10 minutes 
      SELECT 1, 1, 1, '00:00:00' 
UNION ALL SELECT 1, 1, 1, '00:10:00' 
-- [0, 12] - [3, 5] = 10 minutes 
-- or ... [0, 3] + [5, 12] = 10 minutes 
UNION ALL SELECT 2, 1, 2, '00:00:00' 
UNION ALL SELECT 2, 2, 2, '00:03:00' 
UNION ALL SELECT 2, 2, 2, '00:05:00' 
UNION ALL SELECT 2, 1, 2, '00:12:00' 
-- [0, 12] - [3, 5] = 10 minutes 
-- or ... [0, 3] + [5, 12] = 10 minutes 
UNION ALL SELECT 3, 1, 3, '00:00:00' 
UNION ALL SELECT 3, 2, 3, '00:03:00' 
UNION ALL SELECT 3, 2, 3, '00:05:00' 
UNION ALL SELECT 3, 1, 3, '00:12:00' 
UNION ALL SELECT 3, 2, 3, '00:15:00' 
-- [1, 13] - [3, 5] = 10 minutes 
-- or ... [1, 3] + [5, 13] = 10 minutes 
UNION ALL SELECT 4, 2, 4, '00:00:00' 
UNION ALL SELECT 4, 1, 4, '00:01:00' 
UNION ALL SELECT 4, 2, 4, '00:03:00' 
UNION ALL SELECT 4, 2, 4, '00:05:00' 
UNION ALL SELECT 4, 1, 4, '00:13:00' 
UNION ALL SELECT 4, 2, 4, '00:15:00' 
-- [0, 5] + [10, 15] = 10 minutes 
UNION ALL SELECT 5, 1, 5, '00:00:00' 
UNION ALL SELECT 5, 1, 5, '00:05:00' 
UNION ALL SELECT 5, 1, 6, '00:10:00' 
UNION ALL SELECT 5, 1, 6, '00:15:00' 
-- [0, 10] = 10 minutes (ignoring everything inbetween) 
UNION ALL SELECT 6, 1, 7, '00:00:00' 
UNION ALL SELECT 6, 1, 7, '00:03:00' 
UNION ALL SELECT 6, 1, 7, '00:05:00' 
UNION ALL SELECT 6, 1, 7, '00:07:00' 
UNION ALL SELECT 6, 1, 7, '00:10:00' 
-- [0, 11] - [5, 6] = 10 minutes 
-- or ... [0, 3] + [7, 11] = 6 minutes (good) 
-- or ... [0, 5] + [7, 11] = 9 minutes (better) 
UNION ALL SELECT 7, 1, 8, '00:00:00' 
UNION ALL SELECT 7, 1, 8, '00:03:00' 
UNION ALL SELECT 7, 2, 8, '00:05:00' 
UNION ALL SELECT 7, 2, 8, '00:06:00' 
UNION ALL SELECT 7, 1, 8, '00:07:00' 
UNION ALL SELECT 7, 1, 8, '00:11:00' 
-- [0, 1] + [2, 4] + [5, 7] + [8, 13] = 10 
UNION ALL SELECT 8, 1, 9, '00:00:00' 
UNION ALL SELECT 8, 2, 9, '00:01:00' 
UNION ALL SELECT 8, 1, 9, '00:02:00' 
UNION ALL SELECT 8, 1, 9, '00:03:00' 
UNION ALL SELECT 8, 2, 9, '00:04:00' 
UNION ALL SELECT 8, 1, 9, '00:05:00' 
UNION ALL SELECT 8, 1, 9, '00:06:00' 
UNION ALL SELECT 8, 2, 9, '00:07:00' 
UNION ALL SELECT 8, 1, 9, '00:08:00' 
UNION ALL SELECT 8, 1, 9, '00:13:00' 
; 

primo tentativo di approccio ingenuo. Questo dà errori con parti sovrapposte della sessione.

DECLARE @courseid INT; 
SET @courseid = 1; 

SELECT subquery.userid 
, COUNT(DISTINCT subquery.sessionid) AS sessioncount 
, SUM(subquery.duration) AS duration 
, CASE SUM(subquery.duration) 
    WHEN 10 THEN 'ok' 
    ELSE 'ERROR' 
END 
FROM (
    SELECT userid 
    , sessionid 
    , DATEDIFF(MINUTE, MIN(requestdate), MAX(requestdate)) AS duration 
    FROM PageLogSample 
    WHERE courseid = @courseid 
    GROUP BY userid 
    , sessionid 
) subquery 
GROUP BY subquery.userid 
ORDER BY subquery.userid; 

-- userid sessioncount duration 
-- 1  1    10  ok 
-- 2  1    12  ERROR 
-- 3  1    12  ERROR 
-- 4  1    12  ERROR 
-- 5  2    10  ok 

Secondo tentativo. Evitare sovrapposizioni. Funziona solo parzialmente.

DECLARE @courseid INT; 
SET @courseid = 1; 

WITH cte (userid, courseid, sessionid, start, finish, duration) 
AS (
    SELECT userid 
    , courseid 
    , sessionid 
    , MIN(requestdate) 
    , MAX(requestdate) 
    , DATEDIFF(MINUTE, MIN(requestdate), MAX(requestdate)) 
    FROM PageLogSample 
    GROUP BY userid 
    , courseid 
    , sessionid 
) 
SELECT naive.userid 
, naive.sessioncount 
, naive.duration AS naiveduration 
, correction.duration AS correctionduration 
, naive.duration - ISNULL(correction.duration, 0) AS duration 
, CASE naive.duration - ISNULL(correction.duration, 0) 
    WHEN 10 THEN 'ok' 
    ELSE 'ERROR' 
END 
FROM (
    SELECT cte.userid 
    , COUNT(DISTINCT cte.sessionid) AS sessioncount 
    , SUM(cte.duration) AS duration 
    FROM cte 
    WHERE cte.courseid = @courseid 
    GROUP BY cte.userid 
) naive 
LEFT JOIN (
    SELECT errors.userid 
    , SUM(errors.duration) AS duration 
    FROM cte errors 
    WHERE errors.courseid <> @courseid 
    AND EXISTS (
     SELECT * 
     FROM cte 
     WHERE cte.start <= errors.start 
     AND cte.finish >= errors.finish 
     AND cte.courseid = @courseid 
    ) 
    GROUP BY errors.userid 
) correction 
ON naive.userid = correction.userid 
; 

-- userid sessioncount naiveduration correctionduration duration 
-- 1  1    10    NULL    10  ok 
-- 2  1    12    2     10  ok 
-- 3  1    12    NULL    12  ERROR 
-- 4  1    12    NULL    12  ERROR 
-- 5  2    10    NULL    10  ok 

Aggiornamento: Ed Harpers comment mi ha fatto davvero ripensare il mio approccio.

Quindi ecco la terza prova. Qui prima cerco per quali righe rappresentano un'entrata nel corso e che rappresentano qualcuno che parte. Quindi prendo la somma di tutti i tempi di fine e sottrai la somma di tutti i primi. Penso che sia più corretto, mentre non è perfetto.

DECLARE @courseid INT; 
SET @courseid = 1; 

WITH numberedcte (rn, id, userid, courseid, sessionid, requestdate) 
AS (
    SELECT ROW_NUMBER() OVER (PARTITION BY sessionid, userid ORDER BY id) 
    , id 
    , userid 
    , courseid 
    , sessionid 
    , requestdate 
    FROM PageLogSample 
) 
, typedcte (rowtype, id, userid, courseid, sessionid, requestdate, nextrequestdate) 
AS (
    SELECT CASE 
     WHEN previousrequest.courseid = nextrequest.courseid 
      THEN 'between' 
     WHEN previousrequest.courseid IS NULL 
      OR nextrequest.courseid = numberedcte.courseid 
      THEN 'begin' 
     WHEN nextrequest.courseid IS NULL 
      OR previousrequest.courseid = numberedcte.courseid 
      THEN 'end' 
     ELSE 'error?' 
    END AS rowtype 
    , numberedcte.id 
    , numberedcte.userid 
    , numberedcte.courseid 
    , numberedcte.sessionid 
    , numberedcte.requestdate 
    , nextrequest.requestdate 
    FROM numberedcte 
    LEFT JOIN numberedcte previousrequest 
     ON previousrequest.userid = numberedcte.userid 
     AND previousrequest.sessionid = numberedcte.sessionid 
     AND previousrequest.rn = numberedcte.rn - 1 
    LEFT JOIN numberedcte nextrequest 
     ON nextrequest.userid = numberedcte.userid 
     AND nextrequest.sessionid = numberedcte.sessionid 
     AND nextrequest.rn = numberedcte.rn + 1 
    WHERE numberedcte.courseid = @courseid 
    AND (
     nextrequest.courseid = @courseid 
     OR previousrequest.courseid = @courseid 
    ) 
) 
, beginsum (userid, value) 
AS (
    SELECT userid, SUM(DATEPART(MINUTE, requestdate)) 
    FROM typedcte 
    WHERE rowtype = 'begin' 
    GROUP BY userid 
) 
, endsum (userid, value) 
AS (
    SELECT userid, SUM(DATEPART(MINUTE, ISNULL(nextrequestdate, requestdate))) 
    FROM typedcte 
    WHERE rowtype = 'end' 
    GROUP BY userid 
) 
SELECT beginsum.userid 
, endsum.value - beginsum.value AS duration 
FROM beginsum 
INNER JOIN endsum 
    ON beginsum.userid = endsum.userid 
; 

L'unico problema qui è che ottengo l'output per gli utenti 1 e 5 dai miei dati di esempio originali. L'utente aggiunto 6 fornisce anche l'output corretto. L'utente aggiunto 7 mi dà un risultato soddisfacente ora. L'utente 8 è quasi perfetto, mi manca un minuto dalla prima alla seconda.

-- userid duration 
-- 1  10 
-- 5  10 
-- 6  10 
-- 7  9 
-- 8  9 

Mi sento come se fossi a pochi centimetri da ottenere questo completamente giusto. Le uniche durate mancanti sono le pagerequeste che non si sono verificate nei gruppi. Qualcuno può aiutarmi a trovare un modo per ottenere le visualizzazioni di pagina solitarie?

Aggiornamento: Arriva una quarta prova. Qui assegno un valore a ciascuna richiesta e sommario. Non mi dà esattamente l'output che speravo, ma sembra che potrebbe essere abbastanza buono.

DECLARE @courseid INT; 
SET @courseid = 1; 

WITH numberedcte (rn, userid, courseid, sessionid, requestdate) 
AS (
    SELECT ROW_NUMBER() OVER (PARTITION BY sessionid, userid ORDER BY id) 
    , userid 
    , courseid 
    , sessionid 
    , requestdate 
    FROM PageLogSample 
) 
, valuecte (value, userid, courseid, sessionid) 
AS (
    SELECT CASE 
     --alone 
     WHEN (previousrequest.courseid IS NULL 
      OR previousrequest.courseid <> numberedcte.courseid 
      ) 
      AND nextrequest.courseid <> numberedcte.courseid 
      THEN DATEDIFF(MINUTE, numberedcte.requestdate, nextrequest.requestdate) 
     --between 
     WHEN previousrequest.courseid = nextrequest.courseid 
      THEN 0 
     --begin 
     WHEN previousrequest.courseid IS NULL 
      OR nextrequest.courseid = numberedcte.courseid 
      THEN -1 * DATEPART(MINUTE, numberedcte.requestdate) 
     --ignored (end with no next request) 
     WHEN nextrequest.courseid IS NULL 
      AND previousrequest.courseid <> numberedcte.courseid 
      THEN 0 
     --end 
     WHEN nextrequest.courseid IS NULL 
      OR previousrequest.courseid = numberedcte.courseid 
      THEN DATEPART(MINUTE, ISNULL(nextrequest.requestdate, numberedcte.requestdate)) 
     --impossible? 
     ELSE 0 
    END 
    , numberedcte.userid 
    , numberedcte.courseid 
    , numberedcte.sessionid 
    FROM numberedcte 
    LEFT JOIN numberedcte previousrequest 
     ON previousrequest.userid = numberedcte.userid 
     AND previousrequest.sessionid = numberedcte.sessionid 
     AND previousrequest.rn = numberedcte.rn - 1 
    LEFT JOIN numberedcte nextrequest 
     ON nextrequest.userid = numberedcte.userid 
     AND nextrequest.sessionid = numberedcte.sessionid 
     AND nextrequest.rn = numberedcte.rn + 1 
    WHERE numberedcte.courseid = @courseid 
) 
SELECT userid 
, courseid 
, COUNT(DISTINCT sessionid) AS sessioncount 
, SUM(value) AS duration 
FROM valuecte 
GROUP BY userid 
, courseid 
ORDER BY userid 
; 

Come potete vedere i risultati non sono del tutto quello che mi aspettavo.

-- userid courseid sessioncount duration 
-- 1  1   1    10 
-- 2  1   1    3 
-- 3  1   1    6 
-- 4  1   1    4 
-- 5  1   2    10 
-- 6  1   1    10 
-- 7  1   1    9 
-- 8  1   1    10 

Le prestazioni sono orribili nella mia copia locale del database reale. Quindi se qualcuno ha idee su come scriverlo in un modo più performante ... sparare.

Aggiornamento: Le prestazioni sono scadute. Ho aggiunto un indice e ora ha un fascino.

+2

Bella domanda - in termini di script e campione per renderlo più facile da risolvere. – Andrew

+0

La difficoltà con i dati è che il requestdate non ha un significato coerente. A volte è l'ora di inizio e talvolta l'orario di fine di un corso. –

+0

Bel commento alla bella domanda. –

risposta

0

Altri dati di esempio e un'ipotesi logica di quanto tempo ogni utente ha trascorso in ciascun corso.

INSERT INTO PageLogSample (userid, courseid, sessionid, requestdate) 
-- [0, 10] = 10 minutes 
      SELECT 1, 1, 1, '00:00:00' 
UNION ALL SELECT 1, 1, 1, '00:10:00' 
-- [0, 3] = 3 minutes 
-- there is no way to know how long the user was on that last page 
UNION ALL SELECT 2, 1, 2, '00:00:00' 
UNION ALL SELECT 2, 2, 2, '00:03:00' 
UNION ALL SELECT 2, 2, 2, '00:05:00' 
UNION ALL SELECT 2, 1, 2, '00:12:00' 
-- [0, 3] + [12, 15] = 6 minutes 
-- the [5, 12] part was spent on a page of course 2 
UNION ALL SELECT 3, 1, 3, '00:00:00' 
UNION ALL SELECT 3, 2, 3, '00:03:00' 
UNION ALL SELECT 3, 2, 3, '00:05:00' 
UNION ALL SELECT 3, 1, 3, '00:12:00' 
UNION ALL SELECT 3, 2, 3, '00:15:00' 
-- [1, 3] + [13, 15] = 4 minutes 
UNION ALL SELECT 4, 2, 4, '00:00:00' 
UNION ALL SELECT 4, 1, 4, '00:01:00' 
UNION ALL SELECT 4, 2, 4, '00:03:00' 
UNION ALL SELECT 4, 2, 4, '00:05:00' 
UNION ALL SELECT 4, 1, 4, '00:13:00' 
UNION ALL SELECT 4, 2, 4, '00:15:00' 
-- [0, 5] + [10, 15] = 10 minutes 
UNION ALL SELECT 5, 1, 5, '00:00:00' 
UNION ALL SELECT 5, 1, 5, '00:05:00' 
UNION ALL SELECT 5, 1, 6, '00:10:00' 
UNION ALL SELECT 5, 1, 6, '00:15:00' 
-- [0, 10] = 10 minutes (ignoring everything inbetween) 
UNION ALL SELECT 6, 1, 7, '00:00:00' 
UNION ALL SELECT 6, 1, 7, '00:03:00' 
UNION ALL SELECT 6, 1, 7, '00:05:00' 
UNION ALL SELECT 6, 1, 7, '00:07:00' 
UNION ALL SELECT 6, 1, 7, '00:10:00' 
-- [0, 5] + [7, 11] = 9 minutes 
UNION ALL SELECT 7, 1, 8, '00:00:00' 
UNION ALL SELECT 7, 1, 8, '00:03:00' 
UNION ALL SELECT 7, 2, 8, '00:05:00' 
UNION ALL SELECT 7, 2, 8, '00:06:00' 
UNION ALL SELECT 7, 1, 8, '00:07:00' 
UNION ALL SELECT 7, 1, 8, '00:11:00' 
-- [0, 1] + [2, 4] + [5, 7] + [8, 13] = 10 
UNION ALL SELECT 8, 1, 9, '00:00:00' 
UNION ALL SELECT 8, 2, 9, '00:01:00' 
UNION ALL SELECT 8, 1, 9, '00:02:00' 
UNION ALL SELECT 8, 1, 9, '00:03:00' 
UNION ALL SELECT 8, 2, 9, '00:04:00' 
UNION ALL SELECT 8, 1, 9, '00:05:00' 
UNION ALL SELECT 8, 1, 9, '00:06:00' 
UNION ALL SELECT 8, 2, 9, '00:07:00' 
UNION ALL SELECT 8, 1, 9, '00:08:00' 
UNION ALL SELECT 8, 1, 9, '00:13:00' 
-- there is nothing we can say about either of there requests 
-- 0 minutes 
UNION ALL SELECT 9, 1, 10, '00:10:00' 
UNION ALL SELECT 9, 1, 11, '00:20:00' 
; 

Ora otteniamo i nostri dati in questo modo:

WITH numberedcte (rn, userid, courseid, sessionid, requestdate) 
AS (
    SELECT ROW_NUMBER() OVER (PARTITION BY sessionid, userid ORDER BY id) 
    , userid 
    , courseid 
    , sessionid 
    , requestdate 
    FROM PageLogSample 
) 
, valuecte (value, userid, courseid, sessionid) 
AS (
    SELECT CASE 
     --alone in session 
     WHEN previousrequest.courseid IS NULL 
      AND nextrequest.courseid IS NULL 
      THEN 0 
     --alone 
     WHEN (previousrequest.courseid IS NULL 
      OR previousrequest.courseid <> numberedcte.courseid 
      ) 
      AND nextrequest.courseid <> numberedcte.courseid 
      THEN DATEDIFF(MINUTE, numberedcte.requestdate, nextrequest.requestdate) 
     --between 
     WHEN previousrequest.courseid = nextrequest.courseid 
      THEN 0 
     --begin 
     WHEN previousrequest.courseid IS NULL 
      OR nextrequest.courseid = numberedcte.courseid 
      THEN -1 * DATEPART(MINUTE, numberedcte.requestdate) 
     --ignored (end with no next request) 
     WHEN nextrequest.courseid IS NULL 
      AND previousrequest.courseid <> numberedcte.courseid 
      THEN 0 
     --end 
     WHEN nextrequest.courseid IS NULL 
      OR previousrequest.courseid = numberedcte.courseid 
      THEN DATEPART(MINUTE, ISNULL(nextrequest.requestdate, numberedcte.requestdate)) 
     --impossible? 
     ELSE 0 
    END 
    , numberedcte.userid 
    , numberedcte.courseid 
    , numberedcte.sessionid 
    FROM numberedcte 
    LEFT JOIN numberedcte previousrequest 
     ON previousrequest.userid = numberedcte.userid 
     AND previousrequest.sessionid = numberedcte.sessionid 
     AND previousrequest.rn = numberedcte.rn - 1 
    LEFT JOIN numberedcte nextrequest 
     ON nextrequest.userid = numberedcte.userid 
     AND nextrequest.sessionid = numberedcte.sessionid 
     AND nextrequest.rn = numberedcte.rn + 1 
    WHERE numberedcte.courseid = @courseid 
) 
SELECT userid 
, courseid 
, COUNT(DISTINCT sessionid) AS sessioncount 
, SUM(value) AS duration 
FROM valuecte 
GROUP BY userid 
, courseid 
ORDER BY userid 
; 

questo è il risultato che ottengo. Sono piuttosto soddisfatto. Si noti come il conteggio delle sessioni rimane corretto per l'utente 9.

userid courseid sessioncount duration 
1  1   1    10 
2  1   1    3 
3  1   1    6 
4  1   1    4 
5  1   2    10 
6  1   1    10 
7  1   1    9 
8  1   1    10 
9  1   2    0 
0

Ci dispiace, ma penso che tu abbia un problema con i dati. Guardando i dati di esempio forniti dall'utente 2 è in corsoid 1 per 12 minuti e courseid 2 per 2 minuti.

Sei sicuro di aver fornito i dati corretti?

+0

I dati sono corretti, ma è solo difficile ottenere un significato rilevante da esso. L'utente 2 inizia nel corso 1, va al corso 2 per due minuti e poi torna al corso 1. Voglio il tempo che ha trascorso nel corso 1 (10 minuti). Quindi 12 minuti meno i 2 minuti trascorsi in un altro corso. –

+0

Sembra che avessi ragione. La mia interpretazione originale dei dati era imperfetta. –

0

Questo è il più vicino possibile. Non riesce per userid 4.

Come ho detto nel mio commento, requestdate è a volte un inizio e talvolta una fine di un corso, e non riesco a vedere una semplice regola generale per derivare quale ruolo gioca su una determinata riga.

DECLARE @courseid INT; 
SET @courseid = 1; 

WITH orderCTE 
AS 
(
     SELECT * 

       ,ROW_NUMBER() OVER (PARTITION BY sessionid 
            ORDER BY id 
           ) AS rn 
     FROM PageLogSample 
     --order by rn 
) 
,startendCTE 
AS 
(
     SELECT CASE WHEN start1.rn = 1 
        THEN start1.courseid 
        ELSE end1.courseid 
       END courseid 
       ,start1.sessionid 
       ,start1.userid 
       ,DATEDIFF(mi,start1.requestdate,end1.requestdate) duration 
     FROM orderCTE AS start1 
     JOIN orderCTE AS end1 
     ON end1.rn = start1.rn + 1 
     AND end1.sessionid = start1.sessionid 
) 
SELECT courseid 
     ,COUNT(1) sessionCount 
     ,userid 
     ,SUM(duration) totalDuration 
FROM startendCTE 
WHERE courseid = @courseid 
GROUP BY courseid 
     ,userid; 
+0

Mi piace l'idea di cercare prima le righe di inizio e fine. Mi hai ispirato a prendere un nuovo approccio. –

0

Questo è piuttosto disordinato, ma sembra di lavorare per CourseID 1. Non ho provato con altri corsi, quindi si consiglia di verificare che! : D

La premessa di base è che sto ricevendo il tempo tra la prima e l'ultima sessione del CourseID di destinazione e quindi sto sottraendo la durata di tutte le sessioni che non erano del CourseID specificato, ma dove il tempo di richiesta della sessione rientrava nei tempi di richiesta min e max del CourseID targetizzato. Spero che abbia un senso.

La query potrebbe essere risolta, possibilmente con un CTE o qualcosa del genere. Interessante domanda BTW! :)

DECLARE @courseid INT; 
SET @courseid = 1; 

SELECT 
    TargetCourse.UserID, 
    COUNT(Distinct(TargetCourse.SessionID)) as SessionCount, 
    SUM(TargetCourse.Duration - Coalesce(OtherCourses.Duration,0)) as Duration 
FROM 
(
    SELECT 
     TargetCourse.UserID, TargetCourse.SessionID, 
     MIN(TargetCourse.RequestDate) FirstRequest, MAX(TargetCourse.RequestDate) LastRequest, 
     DATEDIFF(MINUTE, MIN(TargetCourse.RequestDate), MAX(TargetCourse.RequestDate)) AS duration 
    FROM 
     PageLogSample TargetCourse 
    WHERE 
     TargetCourse.CourseID = @courseid 
    GROUP BY 
     TargetCourse.UserID, TargetCourse.SessionID  
) as TargetCourse 
LEFT OUTER JOIN 
(
    SELECT 
     OtherCourses.UserID, OtherCourses.SessionID, 
     MIN(OtherCourses.RequestDate) AS FirstRequest, MAX(OtherCourses.RequestDate) AS LastRequest, 
     DATEDIFF(MINUTE, MIN(OtherCourses.RequestDate), MAX(OtherCourses.RequestDate)) AS duration 
    FROM 
     PageLogSample OtherCourses 
    WHERE 
     OtherCourses.CourseID <> @courseid AND 
     OtherCourses.RequestDate between 
      (Select MIN(RequestDate) From PageLogSample T Where T.UserID = OtherCourses.UserID and T.CourseID = @courseid) AND 
      (Select MAX(RequestDate) From PageLogSample T Where T.UserID = OtherCourses.UserID and T.CourseID = @courseid) 
    GROUP BY 
     OtherCourses.UserID, OtherCourses.SessionID 
) as OtherCourses ON 
OtherCourses.UserID = TargetCourse.UserID AND 
OtherCourses.FirstRequest BETWEEN TargetCourse.FirstRequest and TargetCourse.LastRequest 
Group By TargetCourse.UserID 
+0

Molto buono, ma non ancora perfetto. Quando cerchi il tempo da sottrarre, devi tenere a mente che potrebbe esserci più di un "buco" con il courseid. Ho aggiunto un utente aggiuntivo ai dati di esempio per mostrarlo. –

+0

Aha, grazie per averlo indicato. Popolerò l'utente aggiuntivo e gli darò un'altra possibilità. :) – WesleyJohnson

-1

"I dati sono corretti, ma è è solo difficile da ottenere significato rilevante fuori di esso."

Sono spinto a rispondere che questa è una contraddizione di termini. I dati di cui non sai cosa significa non sono dati.

quanto riguarda la tua domanda iniziale:

Quello che vi serve è un DBMS che offre supporto decente per tipi di intervallo. Nessun sistema SQL gioca in quel campionato. A parte alcuni sistemi di tutorial, il mio DBMS (senza spingere ulteriormente in questo contesto, quindi nessun collegamento) è l'unico che conosco che offra il tipo di supporto che è veramente necessario per tali problemi.

Se sei interessato, google in giro per "tipi di intervallo", "formato normale compresso", "dati temporali" e ti verrà eseguito eventualmente.

Problemi correlati