मैं प्रत्येक प्रमुख मूल्य के लिए सबसे हाल के टाइमस्टैम्प के साथ पंक्तियों का चयन कैसे कर सकता हूं?


86

मेरे पास सेंसर डेटा की एक तालिका है। प्रत्येक पंक्ति में एक सेंसर आईडी, एक टाइमस्टैम्प, और अन्य फ़ील्ड हैं। मैं प्रत्येक सेंसर के लिए नवीनतम टाइमस्टैम्प के साथ एक एकल पंक्ति का चयन करना चाहता हूं, जिसमें कुछ अन्य क्षेत्र भी शामिल हैं।

मैंने सोचा था कि समाधान सेंसर आईडी द्वारा समूह के लिए होगा और फिर अधिकतम (टाइमस्टैम्प) द्वारा ऑर्डर करना होगा जैसे:

SELECT sensorID,timestamp,sensorField1,sensorField2 
FROM sensorTable 
GROUP BY sensorID 
ORDER BY max(timestamp);

यह मुझे यह कहते हुए एक त्रुटि देता है कि "SensField1 को समूह में समूह द्वारा प्रकट होना चाहिए या एक समुच्चय में उपयोग किया जाना चाहिए।"

इस समस्या से निपटने का सही तरीका क्या है?


1
आप किस डीबी इंजन का उपयोग कर रहे हैं?
juergen d

1
जबकि मैक्स (टाइमस्टैम्प) मूल्य पर जॉइन का उपयोग करने के लिए नीचे दिए गए उत्तर काम करने चाहिए, मैं आपको SensTReadingId पर शामिल होने का सुझाव दूंगा यदि आपके पास सेंसरटेबल पर एक है।
थॉमस लैंगस्टन

जवाबों:


94

पूर्णता की खातिर, यहां एक और संभव समाधान है:

SELECT sensorID,timestamp,sensorField1,sensorField2 
FROM sensorTable s1
WHERE timestamp = (SELECT MAX(timestamp) FROM sensorTable s2 WHERE s1.sensorID = s2.sensorID)
ORDER BY sensorID, timestamp;

सुंदर आत्म-व्याख्या मुझे लगता है, लेकिन यहाँ अधिक जानकारी है अगर आप चाहें, साथ ही अन्य उदाहरण भी। यह MySQL मैनुअल से है, लेकिन उपरोक्त क्वेरी हर RDBMS (sql'92 मानक को लागू करने) के साथ काम करती है।


56

यह इस तरह से उपयोग करते हुए एक अपेक्षाकृत सुंदर तरीके से किया जा सकता SELECT DISTINCTहै:

SELECT DISTINCT ON (sensorID)
sensorID, timestamp, sensorField1, sensorField2 
FROM sensorTable
ORDER BY sensorID, timestamp DESC;

ऊपर PostgreSQL ( यहाँ कुछ और जानकारी ) के लिए काम करता है, लेकिन मुझे लगता है कि अन्य इंजन भी। यदि यह स्पष्ट नहीं है, तो यह सेंसर आईडी और टाइमस्टैम्प (सबसे पुराना) के अनुसार तालिका को क्रमबद्ध करता है, और फिर प्रत्येक अद्वितीय सेंसर आईडी के लिए पहली पंक्ति (यानी नवीनतम टाइमस्टैम्प) लौटाता है।

मेरे उपयोग के मामले में मेरे पास ~ 1K सेंसर से ~ 10M रीडिंग है, इसलिए टाइमस्टैम्प-आधारित फ़िल्टर पर स्वयं के साथ तालिका में शामिल होने की कोशिश करना बहुत ही संसाधन-गहन है; ऊपर कुछ सेकंड लगते हैं।


यह समाधान वास्तव में तेज है।
Ena

तेज और समझने में आसान। उपयोग मामले को समझाने के लिए धन्यवाद, साथ ही मेरा काफी समान है।
स्टेफ वर्डोंक

दुर्भाग्य से, यह MySQL ( लिंक )
silentsurfer

21

आप खुद से (सेंसर आईडी पर) तालिका में शामिल हो सकते हैं, और left.timestamp < right.timestampजुड़ने की स्थिति में जोड़ सकते हैं। फिर आप पंक्तियों को उठाते हैं, जहां right.idहै null। Voila, आपको प्रति सेंसर नवीनतम प्रविष्टि मिली।

http://sqlfiddle.com/#!9/45147/37

SELECT L.* FROM sensorTable L
LEFT JOIN sensorTable R ON
L.sensorID = R.sensorID AND
L.timestamp < R.timestamp
WHERE isnull (R.sensorID)

लेकिन कृपया ध्यान दें, यदि आपके पास थोड़ी मात्रा में आईडी और कई मूल्य हैं तो यह बहुत ही संसाधन गहन होगा! इसलिए, मैं इसे किसी प्रकार की माप-सामग्री के लिए अनुशंसित नहीं करूंगा, जहां प्रत्येक सेंसर प्रत्येक मिनट में एक मान एकत्र करता है। हालाँकि एक उपयोग-मामले में, जहाँ आपको "कभी-कभी" बदलने वाली किसी चीज़ के "संशोधन" को ट्रैक करने की आवश्यकता होती है, यह आसान है।


यह अन्य उत्तरों की तुलना में तेज है, कम से कम मेरे मामले में।
बारिश_

@rain_ यह वास्तव में उपयोग के मामले पर निर्भर करता है। इसलिए, इस सवाल का कोई "सार्वभौमिक जवाब" नहीं है।
१६:

19

आप केवल उन कॉलम का चयन कर सकते हैं जो समूह में हैं या एक कुल फ़ंक्शन में उपयोग किए जाते हैं। इस कार्य को करने के लिए आप एक जॉइन का उपयोग कर सकते हैं

select s1.* 
from sensorTable s1
inner join 
(
  SELECT sensorID, max(timestamp) as mts
  FROM sensorTable 
  GROUP BY sensorID 
) s2 on s2.sensorID = s1.sensorID and s1.timestamp = s2.mts

... या select * from sensorTable where (sensorID, timestamp) in (select sensorID, max(timestamp) from sensorTable group by sensorID)
अर्जन

मुझे लगता है कि "LEFT JOIN" को केवल "INNER JOIN" के रूप में लागू किया जाता है; और एक हिस्सा "और s1.timestamp = s2.mts" nessesary IMHO नहीं है। और फिर भी, मैं दो क्षेत्रों पर सूचकांक बनाने की सलाह देता हूं: सेंसरआईडी + टाइमस्टैम्प - क्वेरी की गति बहुत बढ़ जाती है!
इगोर

4
WITH SensorTimes As (
   SELECT sensorID, MAX(timestamp) "LastReading"
   FROM sensorTable
   GROUP BY sensorID
)
SELECT s.sensorID,s.timestamp,s.sensorField1,s.sensorField2 
FROM sensorTable s
INNER JOIN SensorTimes t on s.sensorID = t.sensorID and s.timestamp = t.LastReading

2

एक सामान्य उत्तर है जो मैंने अभी तक यहां नहीं देखा है, जो कि विंडो फ़ंक्शन है। यह सह-संबद्ध उप-क्वेरी का एक विकल्प है, यदि आपका DB इसका समर्थन करता है।

SELECT sensorID,timestamp,sensorField1,sensorField2 
FROM (
    SELECT sensorID,timestamp,sensorField1,sensorField2
        , ROW_NUMBER() OVER(
            PARTITION BY sensorID
            ORDER BY timestamp
        ) AS rn
    FROM sensorTable s1
WHERE rn = 1
ORDER BY sensorID, timestamp;

मैं इसे सहसंबद्ध उप-प्रश्नों से अधिक उपयोग करता हूं। बेझिझक टिप्पणियों पर मुझे बस्ट करने के लिए बेझिझक, मुझे यकीन नहीं है कि यह उस संबंध में कैसे ढेर हो जाता है।


0

मैं ज्यादातर एक ही समस्या थी और एक अलग समाधान है कि इस तरह की समस्या को क्वेरी के लिए तुच्छ बनाता है।

मेरे पास सेंसर डेटा की तालिका है (लगभग 30 सेंसर से 1 मिनट का डेटा)

SensorReadings->(timestamp,value,idSensor)

और मेरे पास एक सेंसर टेबल है जिसमें सेंसर के बारे में ज्यादातर स्थिर चीजें हैं लेकिन संबंधित फ़ील्ड ये हैं:

Sensors->(idSensor,Description,tvLastUpdate,tvLastValue,...)

TVLastupdate और TVLastValue आवेषण पर SensorReadings तालिका में एक ट्रिगर में सेट किए गए हैं। मुझे हमेशा किसी भी महंगी क्वेरी करने की आवश्यकता के बिना इन मूल्यों तक सीधी पहुंच है। यह थोड़ा असामान्य है। क्वेरी तुच्छ है:

SELECT idSensor,Description,tvLastUpdate,tvLastValue 
FROM Sensors

मैं इस पद्धति का उपयोग डेटा के लिए करता हूं जो अक्सर क्वेराइड होता है। मेरे मामले में मेरे पास एक सेंसर टेबल, और एक बड़ी घटना तालिका है, जिसमें मिनट के स्तर पर डेटा आ रहा है और दर्जनों मशीनें उस डेटा के साथ डैशबोर्ड और ग्राफ़ को अपडेट कर रही हैं। मेरे डेटा परिदृश्य के साथ ट्रिगर और कैश विधि अच्छी तरह से काम करती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.