2009-10-23 9 views
7

मेरे पास एक सारणी है जो प्रत्येक बार वेबपृष्ठ लोड होने पर उपयोगकर्ता आईडी, कोर्स, सत्रिड और अनुरोध दिनांक लॉग करता है। मैं एक दिए गए पाठ्यक्रम के लिए प्रति उपयोगकर्ता आईडी की अवधि को कैलकुलेट करना चाहता हूं। अतिव्यापी टाइमपैंस के कारण ऐसा करना समस्याग्रस्त है।लॉग तालिका से यात्रा अवधि के भाग की गणना करने के लिए एसक्यूएल क्वेरी

यहां प्रदान किया गया डेटा पाठ्यक्रम के लिए प्रति उपयोगकर्ता 10 मिनट की अवधि के परिणामस्वरूप होना चाहिए। मुझे यह अधिकार नहीं मिल रहा है।

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

पहले बेवकूफ दृष्टिकोण की कोशिश कर रहा है। यह सत्र के ओवरलैपिंग भागों के साथ गलती देता है।

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 

दूसरा प्रयास। ओवरलैपिंग से बचें। यह केवल आंशिक रूप से काम करता है।

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 

अद्यतन: Ed Harpers comment सच मुझे मेरे दृष्टिकोण पर पुनर्विचार कर दिया।

तो यहां तीसरा परीक्षण आता है। यहां मैं पहली बार खोज करता हूं कि कौन सी पंक्तियां पाठ्यक्रम में प्रवेश द्वार का प्रतिनिधित्व करती हैं और जो किसी को छोड़कर प्रतिनिधित्व करती हैं। फिर मैं सभी अंतराल का योग लेता हूं और सभी शुरुआती दिनों के योग को घटा देता हूं। मुझे लगता है कि यह सही नहीं है, जबकि यह सही है।

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 
; 

यहां केवल समस्या यह है कि मैं सिर्फ अपने मूल नमूना डेटा से उपयोगकर्ता 1 और 5 के लिए आउटपुट प्राप्त है। जोड़ा गया उपयोगकर्ता 6 भी सही आउटपुट देता है। जोड़ा गया उपयोगकर्ता 7 अब मुझे एक संतोषजनक आउटपुट देता है। उपयोगकर्ता 8 लगभग सही है, मुझे पहली पंक्ति से दूसरी पंक्ति में एक मिनट याद आती है।

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

मुझे लगता है कि मैं इसे पूरी तरह से सही करने से इंच दूर हूं। गायब होने वाली एकमात्र अवधि पृष्ठ की जांच से होती है जो समूहों में नहीं होती है। क्या कोई अकेला पृष्ठदृश्य प्राप्त करने का तरीका ढूंढने में मेरी सहायता कर सकता है?

अद्यतन: यहां चौथा परीक्षण आता है। यहां मैं प्रत्येक अनुरोध के लिए एक मान आवंटित करता हूं और उन्हें जोड़ता हूं। यह मुझे आउटपुट को सटीक नहीं देता है, लेकिन ऐसा लगता है कि यह काफी अच्छा हो सकता है।

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 
; 

जैसा कि आप देख सकते हैं कि परिणाम पूरी तरह से अपेक्षित नहीं हैं।

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

प्रदर्शन वास्तविक डेटाबेस की मेरी स्थानीय प्रति पर भयानक है। तो अगर किसी के पास विचारों को एक और अधिक प्रदर्शन करने के तरीके के रूप में लिखने के लिए है ... शूट करें।

अद्यतन: प्रदर्शन ऊपर है। मैंने एक इंडेक्स जोड़ा और यह अब एक आकर्षण काम करता है।

+2

अच्छा प्रश्न - स्क्रिप्ट और नमूना के संदर्भ में इसे हल करना आसान बनाता है। – Andrew

+0

डेटा के साथ कठिनाई यह है कि अनुरोधकर्ता का कोई निरंतर अर्थ नहीं है। कभी-कभी प्रारंभ समय और कभी-कभी पाठ्यक्रम का अंत समय होता है। –

+0

अच्छे प्रश्न के लिए अच्छी टिप्पणी। –

उत्तर

0

कुछ और नमूना डेटा और आशा है कि प्रत्येक उपयोगकर्ता प्रत्येक पाठ्यक्रम में कितना समय बिताता है।

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

अब हम इस तरह हमारे डेटा प्राप्त:

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 
; 

यह परिणाम मैं हो रही है। मैं इसके साथ बहुत खुश हूँ। ध्यान दें कि उपयोगकर्ता के लिए सत्र गणना सही कैसे होती है 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

क्षमा करें, लेकिन मुझे लगता है कि आपके पास डेटा समस्या है। प्रदान किए गए नमूना डेटा को देखते हुए उपयोगकर्ता 2 निश्चित रूप से 12 मिनट के लिए 1 और 2 मिनट के लिए पाठ्यक्रम 2 है।

क्या आप वाकई सही डेटा प्रदान कर चुके हैं?

+0

डेटा सही है, लेकिन इसमें से प्रासंगिक अर्थ प्राप्त करना मुश्किल है। उपयोगकर्ता 2 निश्चित रूप से 1 से शुरू होता है, दो मिनट के लिए कोर्स 2 पर जाता है और फिर पाठ्यक्रम 1 पर लौटाता है। मुझे वह समय चाहिए जब वह 1 (10 मिनट) खर्च करता है। इस प्रकार 12 मिनट से कम 2 मिनट में उन्होंने एक और पाठ्यक्रम में बिताया। –

+0

ऐसा लगता है कि आप सही थे। डेटा की मेरी मूल व्याख्या त्रुटिपूर्ण थी। –

0

यह उतना करीब है जितना मैं प्राप्त कर सकता हूं। यह उपयोगकर्ता आईडी 4 के लिए विफल रहता है।

जैसा कि मैंने अपनी टिप्पणी में कहा था, requestdate कभी-कभी एक शुरुआत होती है और कभी-कभी एक कोर्स का अंत होता है, और मुझे किसी दिए गए पंक्ति पर कौन सी भूमिका निभाती है, यह जानने के लिए मुझे एक सामान्य सामान्य नियम नहीं दिखाई दे रहा है।

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

मुझे शुरुआत और अंत-पंक्तियों की खोज करने का विचार पसंद है। आपने मुझे एक नया दृष्टिकोण लेने के लिए प्रेरित किया है। –

0

यह सुंदर गंदा है, लेकिन यह मैं अन्य पाठ्यक्रमों के साथ यह कोशिश नहीं की है, तो आप कि परीक्षण करने के लिए चाहते हो सकता है CourseID 1. के लिए काम कर रहा है! : डी

मूल आधार यह है कि मुझे लक्ष्य कोर्स आईडी के पहले और अंतिम सत्र के बीच समय की अवधि मिल रही है और फिर मैं निर्दिष्ट पाठ्यक्रम आईडी के किसी भी सत्र की अवधि घटा रहा हूं, लेकिन जहां सत्र अनुरोध समय लक्षित पाठ्यक्रम आईडी के न्यूनतम और अधिकतम अनुरोध समय के भीतर गिर गया। मुझे उम्मीद है कि इसका कोई अर्थ है।

क्वेरी निश्चित रूप से सीटीई या कुछ के साथ साफ हो सकती है। दिलचस्प सवाल बीटीडब्ल्यू! :)

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

बहुत अच्छा, लेकिन अभी तक सही नहीं है। जब आप घटाने के लिए समय खोजते हैं तो आपको ध्यान में रखना होगा कि कुछ पाठ्यक्रम के साथ एक से अधिक "अंतर" हो सकता है। मैंने इसे दिखाने के लिए नमूना डेटा में एक अतिरिक्त उपयोगकर्ता जोड़ा। –

+0

आह, इसे इंगित करने के लिए धन्यवाद। मैं अतिरिक्त उपयोगकर्ता को पॉप्युलेट कर दूंगा और इसे एक और जाना दूंगा। :) – WesleyJohnson

-1

"डेटा सही है, लेकिन इसके बारे में प्रासंगिक अर्थ प्राप्त करना मुश्किल है।"

मुझे जवाब देने के लिए दबाया गया है कि यह शर्तों का एक विरोधाभास है। जिस डेटा का आप नहीं जानते कि इसका क्या अर्थ है डेटा नहीं है।

अपने मूल प्रश्न के लिए के रूप में:

आपको क्या करना होगा एक डीबीएमएस अंतराल प्रकार के लिए सभ्य समर्थन प्रदान करता है। उस लीग में कोई एसक्यूएल सिस्टम नहीं चलता है। कुछ ट्यूटोरियल सिस्टम के अलावा, मेरे स्वयं के डीबीएमएस (इस संदर्भ में कोई आगे नहीं बढ़ते, इसलिए कोई लिंक नहीं) केवल मुझे पता है कि इस तरह की समस्याओं के लिए वास्तव में आवश्यक समर्थन प्रदान करता है।

यदि आप रुचि रखते हैं, तो "अंतराल प्रकार", "सामान्य रूप से पैक", "अस्थायी डेटा" के लिए Google पर जाएं और आप अंततः इसमें भाग लेंगे।