2012-04-04 11 views
5

मैं संरचना के साथ एक MySQL तालिका है की अधिकतम अवधि तक जाँच हो रही है:लगातार दिन जो विशिष्ट शर्त पूरी

beverages_log (आईडी, users_id, beverages_id, टाइमस्टैम्प)

मैं अधिकतम लकीर गणना करने के लिए कोशिश कर रहा हूँ लगातार दिनों के दौरान एक उपयोगकर्ता (आईडी 1 के साथ) प्रत्येक दिन कम से कम 5 बार एक पेय (आईडी 1 के साथ) लॉग करता है। मैं बहुत यकीन है कि यह विचारों का उपयोग इस प्रकार किया जा सकता है कि कर रहा हूँ:

CREATE or REPLACE VIEW daycounts AS 
SELECT count(*) AS n, DATE(timestamp) AS d FROM beverages_log 
WHERE users_id = '1' AND beverages_id = 1 GROUP BY d; 

CREATE or REPLACE VIEW t AS SELECT * FROM daycounts WHERE n >= 5; 

SELECT MAX(streak) AS current FROM (SELECT DATEDIFF(MIN(c.d), a.d)+1 AS streak 
FROM t AS a LEFT JOIN t AS b ON a.d = ADDDATE(b.d,1) 
LEFT JOIN t AS c ON a.d <= c.d 
LEFT JOIN t AS d ON c.d = ADDDATE(d.d,-1) 
WHERE b.d IS NULL AND c.d IS NOT NULL AND d.d IS NULL GROUP BY a.d) allstreaks; 

हालांकि, विभिन्न उपयोगकर्ताओं के लिए विचारों को बार-बार बनाने हर बार जब मैं इस जांच चलाने सुंदर अक्षम लगता है। क्या MySQL में एक ही प्रश्न में इस गणना को निष्पादित करने के लिए कोई तरीका है, बिना विचार किए या बार-बार समान सबक्विरीज़ को बार-बार बुलाते हुए?

उत्तर

6

यह समाधान बहुत अच्छी तरह से लंबे समय के रूप में प्रदर्शन करने के लिए के रूप में वहाँ users_id पर एक समग्र सूचकांक है लगता है और beverages_id -

SELECT * 
FROM (
    SELECT t.*, IF(@prev + INTERVAL 1 DAY = t.d, @c := @c + 1, @c := 1) AS streak, @prev := t.d 
    FROM (
     SELECT DATE(timestamp) AS d, COUNT(*) AS n 
     FROM beverages_log 
     WHERE users_id = 1 
     AND beverages_id = 1 
     GROUP BY DATE(timestamp) 
     HAVING COUNT(*) >= 5 
    ) AS t 
    INNER JOIN (SELECT @prev := NULL, @c := 1) AS vars 
) AS t 
ORDER BY streak DESC LIMIT 1; 
+0

हाँ, यह अच्छी तरह से काम करता है - धन्यवाद! मुझे यकीन नहीं है कि मैं पूरी तरह से समझता हूं "अंदरूनी जॉइन (SELECT @prev: = NULL, @c: = 1) AS vars" - क्या यह चर को साफ़ करने के लिए है? –

+0

यह सुनिश्चित करने के लिए है कि उनके पास क्वेरी के पिछले भाग से कोई मान नहीं है। – nnichols

+0

गोचा। एक और सवाल - यह कैसे है कि @prev वास्तव में पिछली पंक्ति की तारीख का जिक्र कर रहा है? ऐसा लगता है कि अगर इसे "@prev: = t.d" के रूप में परिभाषित किया गया है, तो यह केवल वर्तमान पंक्ति की तारीख देगा। –

0

उपयोगकर्ता_आईडी और डेट द्वारा दिन-दर-दिन दृश्य और समूह में उपयोगकर्ता_आईडी क्यों शामिल नहीं है।

उपयोगकर्ता आईडी को देखने में भी शामिल है।

तब जब आप टी के खिलाफ queering कर रहे हैं उपयोगकर्ता clid जहां खंड में जोड़ें।

फिर आपको अपने प्रत्येक क्लॉज में शामिल करने के लिए याद रखने वाले प्रत्येक उपयोगकर्ता के लिए अपने विचारों को फिर से बनाने की आवश्यकता नहीं है।

0

यह थोड़ा मुश्किल है। सभी संभव तिथि सीमाओं की जांच करने और;

CREATE VIEW BView AS 
    SELECT UserID, BevID, CAST(EventDateTime AS DATE) AS EventDate, COUNT(*) AS NumEvents 
    FROM beverages_log 
    GROUP BY UserID, BevID, CAST(EventDateTime AS DATE) 

मैं चाहते तो (बहुत आसान है करने के लिए प्रति दिन एक पंक्ति के साथ सिर्फ एक मेज) एक तिथियां तालिका का उपयोग: मैं दिन-ब-घटनाओं को संक्षेप में प्रस्तुत करने की दृष्टि से शुरुआत करते हैं, किसी भी अंतर के साथ बाहर फेंक दें। यह शायद नरक के रूप में धीमी गति से हो जाएगा, लेकिन यह एक शुरुआत है:

SELECT 
    UserID, BevID, MAX(StreakLength) AS StreakLength 
FROM 
    (
    SELECT 
     B1.UserID, B1.BevID, B1.EventDate AS StreakStart, DATEDIFF(DD, StartDate.Date, EndDate.Date) AS StreakLength 
    FROM 
     BView AS B1 
     INNER JOIN Dates AS StartDate ON B1.EventDate = StartDate.Date 
     INNER JOIN Dates AS EndDate ON EndDate.Date > StartDate.Date 
    WHERE 
      B1.NumEvents >= 5 
     -- Exclude this potential streak if there's a day with no activity 
     AND NOT EXISTS (SELECT * FROM Dates AS MissedDay WHERE MissedDay.Date > StartDate.Date AND MissedDay.Date <= EndDate.Date AND NOT EXISTS (SELECT * FROM BView AS B2 WHERE B1.UserID = B2.UserID AND B1.BevID = B2.BevID AND MissedDay.Date = B2.EventDate)) 
     -- Exclude this potential streak if there's a day with less than five events 
     AND NOT EXISTS (SELECT * FROM BView AS B2 WHERE B1.UserID = B2.UserID AND B1.BevID = B2.BevID AND B2.EventDate > StartDate.Date AND B2.EventDate <= EndDate.Date AND B2.NumEvents < 5) 
    ) AS X 
GROUP BY 
    UserID, BevID 
+0

के रूप में लिखा है, यह दो दिन की लकीर के रूप में 04/02 से 04/04 की गणना करता है, क्योंकि तिथियों का अंतर दो है। यदि आप इसे तीन दिनों के रूप में सोचते हैं, तो बस एक जोड़ें। वास्तव में 'DATEDIFF()' के बजाय 'COUNT (*)' का उपयोग करके उस परिणाम को भी देना चाहिए। –

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