2015-06-04 10 views
5

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

+----------------------+---------------+---------------------+-------------------+ 
| activity_client_id | activity_type | activity_start_date | activity_end_date | 
+----------------------+---------------+---------------------+-------------------+ 
|     112 | Interview  | 2015-06-01 09:00 | 2015-06-01 11:00 | 
|     112 | CV updating | 2015-06-01 09:30 | 2015-06-01 11:30 | 
|     112 | Course  | 2015-06-02 09:00 | 2015-06-02 16:00 | 
|     112 | Interview  | 2015-06-03 09:00 | 2015-06-03 10:00 | 
+----------------------+---------------+---------------------+-------------------+ 

प्रत्येक ग्राहक के पास क्लाइंट टेबल पर दर्ज "साइन अप डेट" होता है, जो तब होता है जब वे हमारे कार्यक्रम में शामिल होते हैं। यहाँ यह हमारे नमूना ग्राहक के लिए है:

+-----------+---------------------+--------------------------------------------+ 
| client_id | client_sign_up_date | date_client_completed_5_hours_of_activity | 
+-----------+---------------------+--------------------------------------------+ 

हम देखना चाहते हैं कि प्रभावी हमारे कार्यक्रम है में इस रिपोर्ट की जरूरत है:

+-----------+---------------------+ 
| client_id | client_sign_up_date | 
+-----------+---------------------+ 
|  112 | 2015-05-20   | 
+-----------+---------------------+ 

मैं एक रिपोर्ट है कि निम्न स्तंभ दिखाएगा बनाना होगा। कार्यक्रम का एक महत्वपूर्ण उद्देश्य यह है कि हम प्रत्येक ग्राहक को जितनी जल्दी हो सके कम से कम 5 घंटे की गतिविधि को पूरा करने के लिए प्राप्त करते हैं। तो यह रिपोर्ट हमें बताएगी कि इस आंकड़े को प्राप्त करने के लिए प्रत्येक ग्राहक को साइन अप करने में कितना समय लगता है।

ग्राहक ऊपर नमूना डेटा में 09:00 और 11:00 बजे के बीच एक साक्षात्कार में भाग लिया:

क्या यह भी जटिल बना देता है कि जब हम कुल गतिविधि के 5 घंटे की गणना, हम ओवरलैपिंग गतिविधियों छूट चाहिए।
उसी दिन उन्होंने सीवी अपडेटिंग गतिविधि को 09:30 से 11:30 तक भी किया। हमारी गणना के लिए, यह उन्हें 2.5 घंटे (150 मिनट) के दिन के लिए कुल गतिविधि देगा - हम केवल सीवी अपडेटिंग के 30 मिनट की गणना करेंगे क्योंकि साक्षात्कार इसे 11:00 तक ओवरलैप करता है।

तो हमारे नमूना ग्राहक निम्न परिणाम देना होगा के लिए रिपोर्ट:

+-----------+---------------------+--------------------------------------------+ 
| client_id | client_sign_up_date | date_client_completed_5_hours_of_activity | 
+-----------+---------------------+--------------------------------------------+ 
|  112 | 2015-05-20   | 2015-06-02         | 
+-----------+---------------------+--------------------------------------------+ 

तो मेरे सवाल है मैं एक का चयन करें कथन का उपयोग रिपोर्ट कैसे बना सकते हैं? मैं एक संग्रहित प्रक्रिया लिखकर ऐसा कैसे कर सकता हूं जो दृश्य के माध्यम से लूप करेगा और परिणाम रिपोर्ट तालिका में लिख देगा। लेकिन मैं संग्रहित प्रक्रिया से बचने के लिए बहुत पसंद करूंगा और एक चुनिंदा बयान दूंगा जो मुझे फ्लाई पर रिपोर्ट देगा।

;WITH CTErn AS (
    SELECT activity_client_id, activity_type, 
      activity_start_date, activity_end_date, 
      ROW_NUMBER() OVER (PARTITION BY activity_client_id 
          ORDER BY activity_start_date) AS rn 
    FROM activities 
), 
CTEdiff AS (
    SELECT c1.activity_client_id, c1.activity_type, 
      x.activity_start_date, c1.activity_end_date, 
      DATEDIFF(mi, x.activity_start_date, c1.activity_end_date) AS diff, 
      ROW_NUMBER() OVER (PARTITION BY c1.activity_client_id 
          ORDER BY x.activity_start_date) AS seq 
    FROM CTErn AS c1 
    LEFT JOIN CTErn AS c2 ON c1.rn = c2.rn + 1 
    CROSS APPLY (SELECT CASE 
          WHEN c1.activity_start_date < c2.activity_end_date 
          THEN c2.activity_end_date 
          ELSE c1.activity_start_date 
         END) x(activity_start_date)  
) 
SELECT TOP 1 client_id, client_sign_up_date, activity_start_date, 
      hoursOfActivicty    
FROM CTEdiff AS c1 
INNER JOIN clients AS c2 ON c1.activity_client_id = c2.client_id      
CROSS APPLY (SELECT SUM(diff)/60.0 
      FROM CTEdiff AS c3 
      WHERE c3.seq <= c1.seq) x(hoursOfActivicty) 
WHERE hoursOfActivicty >= 5 
ORDER BY seq 

आम टेबल भाव और ROW_NUMBER() SQL सर्वर 2005 के साथ शुरू किए गए थे, इसलिए ऊपर क्वेरी काम करना चाहिए:

मैं एसक्यूएल सर्वर 2005

+0

क्या हम मान सकते हैं कि ऐसी कोई अवधि नहीं है जो * सटीक * एक-दूसरे को ओवरलैप करें? –

+0

@ डेमियन। इसकी बहुत पतली संभावना है, लेकिन मुझे लगता है कि हम इसे अभी अनदेखा कर सकते हैं अगर इसका मतलब है कि हमें सही समय 99.99% सही डेटा मिलता है, – Brian

उत्तर

1

उपयोग कर रहा हूँ यह एक तरीका है यह करने के लिए है उस संस्करण के लिए।

client_id activity_type start_date   end_date   rn 
112   Interview  2015-06-01 09:00 2015-06-01 11:00 1 
112   CV updating  2015-06-01 09:30 2015-06-01 11:30 2 
112   Course   2015-06-02 09:00 2015-06-02 16:00 3 
112   Interview  2015-06-03 09:00 2015-06-03 10:00 4 

दूसरा CTE है, अर्थात:

Demo here

पहले CTE, अर्थात CTErn, निम्नलिखित उत्पादन का उत्पादनCTEdiff, प्रत्येक रिकॉर्ड के लिए समय अंतर की गणना करने के पिछले रिकॉर्ड के साथ किसी भी overlapps को ध्यान में लेने के क्रम में उपरोक्त तालिका अभिव्यक्ति का उपयोग करता है:

client_id activity_type start_date  end_date   diff seq 
112  Interview  2015-06-01 09:00 2015-06-01 11:00 120 1 
112  CV updating 2015-06-01 11:00 2015-06-01 11:30 30 2 
112  Course  2015-06-02 09:00 2015-06-02 16:00 420 3 
112  Interview  2015-06-03 09:00 2015-06-03 10:00 60 4 

अंतिम क्वेरी समय अंतर के संचयी योग की गणना करता है और पहले रिकॉर्ड का चयन करता है कि गतिविधि के 5 घंटे से अधिक है।

उपर्युक्त क्वेरी सरल अंतराल ओवरलैप के लिए काम करेगी, यानी जब किसी गतिविधि की समाप्ति तिथि अगली गतिविधि की आरंभ तिथि को ओवरलैप करती है।

+0

धन्यवाद, यह बहुत अच्छा लगता है। सभी ग्राहकों में इस क्वेरी को चलाने में बहुत लंबा समय लगता है। इसलिए मैं क्लाइंट टेबल "5_hours_of_activity_date" में एक नया कॉलम जोड़ रहा हूं। मैं एक संग्रहित प्रक्रिया बनाता हूं जो प्रत्येक क्लाइंट के लिए नए कॉलम को अपडेट करने के लिए उपरोक्त कोड का उपयोग करके हर रात चलता है। – Brian

2

एसक्यूएल फिडल here देखें।

with tbl as (
    -- this will generate daily merged ovelaping time 
    select distinct 
    a.id 
    ,(
     select min(x.starttime) 
     from act x 
     where x.id=a.id and (x.starttime between a.starttime and a.endtime 
      or a.starttime between x.starttime and x.endtime) 
    ) start1 
    ,(
     select max(x.endtime) 
     from act x 
     where x.id=a.id and (x.endtime between a.starttime and a.endtime 
      or a.endtime between x.starttime and x.endtime) 
    ) end1 
    from act a 

), tbl2 as 
(
    -- this will add minute and total minute column 
    select 
    * 
    ,datediff(mi,t.start1,t.end1) mi 
    ,(select sum(datediff(mi,x.start1,x.end1)) from tbl x where x.id=t.id and x.end1<=t.end1) totalmi 
    from tbl t 
), tbl3 as 
(
    -- now final query showing starttime and endtime for 5 hours other wise null in case not completed 5(300 minutes) hours 
    select 
    t.id 
    ,min(t.start1) starttime 
    ,min(case when t.totalmi>300 then t.end1 else null end) endtime 
    from tbl2 t 
    group by t.id 
) 
-- final result 
select * 
from tbl3 
where endtime is not null 
+0

धन्यवाद, यह भी बहुत अच्छा लग रहा है। मैं यह देखने के लिए नीचे और @Giorgos उत्तर दोनों के साथ प्रयोग करने जा रहा हूं यह देखने के लिए कि कौन सबसे कुशलता से चलता है। – Brian

संबंधित मुद्दे