मेरे पास डेटा है जो कुछ ऐसा है:

+------------+---------+-------+
|    Name    |  Time   | Flag  |
+------------+---------+-------+
| Bob        | 401     | 1     |
| Bob        | 204     | 0     |
| Dan        | 402     | 1     |
| Dan        | 210     | 0     |
| Jeff       | 204     | 0     |
| Fred       | 407     | 1     |
| Mike       | 415     | 1     |
| Mike       | 238     | 0     |
+------------+---------+-------+

मैं प्रत्येक व्यक्ति का सर्वश्रेष्ठ समय प्राप्त करना चाहता हूं, लेकिन यदि "झंडा" सेट है, तो उनके समय को 2 से विभाजित किया जाना चाहिए। उदाहरण के लिए, बॉब का सबसे अच्छा समय 200.5 होगा।

अब मैं इस डेटा को इस तरह प्राप्त करने के लिए अपेक्षाकृत सरल क्वेरी कर सकता हूं:

SELECT userid,
       MIN(CASE WHEN flag = 1 THEN time / 2 ELSE time END) AS convertedTime,
       time,
       flag
FROM   times t
GROUP  BY userid
ORDER  BY convertedtime ASC

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

Bob     200.5   204     0

सही डेटा के बजाय

Bob     200.5   401     1

बेशक मैं पिछली क्वेरी के साथ समस्या देखता हूं और मैंने इसे इसके साथ ठीक कर दिया है:

 SELECT userid,
       MIN(convertedtime) AS convertedTime,
       (SELECT time
        FROM   times
        WHERE  MIN(convertedtime) = CASE
                                      WHEN flag = 1 THEN time / 2
                                      ELSE time
                                    end
        LIMIT  1)         AS time,
       (SELECT flag
        FROM   times
        WHERE  MIN(convertedtime) = CASE
                                      WHEN flag = 1 THEN time / 2
                                      ELSE time
                                    end
        LIMIT  1)         AS flag
FROM   (SELECT userid,
               CASE
                 WHEN flag = 1 THEN time / 2
                 ELSE time
               end AS convertedTime,
               time,
               flag
        FROM   times t) AS t
GROUP  BY userid
ORDER  BY convertedtime ASC

SQLFiddle

यह काम करता है, लेकिन मुझे लगता है कि ऐसा करने का एक बेहतर और अधिक कुशल तरीका होना चाहिए। मेरी वास्तविक क्वेरी में, जिस हिस्से में मैं समय को 2 से विभाजित कर रहा हूं वह बहुत लंबा फॉर्मूला है और मेरे पास हजारों पंक्तियां हैं इसलिए यह बहुत धीमी है।

तो सवाल यह है कि क्या इसके लिए कोई बेहतर/अधिक कुशल प्रश्न है?

0
abney317 7 नवम्बर 2017, 00:30

2 जवाब

सबसे बढ़िया उत्तर

SQL से एक सामान्य तकनीक का उपयोग करें केवल चयन करें कॉलम पर अधिकतम मान वाली पंक्तियाँ लेकिन ON स्थिति में मानों की तुलना करते समय flag चेक जोड़ें।

SELECT t1.username, t2.convertedtime, t1.time, t1.flag
FROM times AS t1
JOIN (SELECT username,
             MIN(IF(flag = 1, time/2, time) AS convertedtime
      FROM times
      GROUP BY username) AS t2
ON t1.username = t2.username
AND t1.time = IF(t1.flag = 1, t2.convertedtime * 2, t2.convertedtime)

यह शायद बहुत कुशल नहीं होगा - मुझे नहीं लगता कि यह सशर्त तुलना के लिए एक इंडेक्स का उपयोग करने में सक्षम होगा।

1
Barmar 7 नवम्बर 2017, 01:03

यही वह है जिसका मैंने उपयोग करके समाप्त किया (इस मामले में संख्या को वापस करने के लिए 2 से गुणा नहीं किया जा सकता है क्योंकि इसमें मेरी अधिक जटिल वास्तविक क्वेरी गोल हो रही है), लेकिन बरमार ने वही काम किया जैसा मैं कर रहा हूं इसलिए मैंने चिह्नित किया उसके उत्तर के रूप में।

SELECT times.userID, times2.convertedTime, times.time, times.flag
FROM times JOIN
(
SELECT userid,
       MIN(CASE WHEN flag = 1 THEN time / 2 ELSE time END) AS convertedTime,
       time,
       flag
FROM   times t
GROUP  BY userid
ORDER  BY convertedtime ASC
) as times2 ON times.userid = times2.userid AND 
(
  (times.time / 2 = times2.convertedTime AND times.flag = 1) OR 
  (times.time = times2.convertedTime AND times.flag = 0)
)
0
abney317 7 नवम्बर 2017, 01:19