MySQL में ROW_NUMBER ()


281

SQL सर्वर फ़ंक्शन को दोहराने के लिए MySQL में एक अच्छा तरीका है ROW_NUMBER()?

उदाहरण के लिए:

SELECT 
    col1, col2, 
    ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1

फिर, मैं उदाहरण के लिए, प्रत्येक जोड़ी के लिए intRowउच्चतम के साथ एक एकल पंक्ति प्राप्त करने के लिए 1 तक सीमित करने के लिए एक शर्त जोड़ सकता हूं ।col3(col1, col2)


9
greatest-n-per-groupइसी तरह के सवालों के लिए आपका मार्गदर्शन करने के लिए टैग किया गया।
बिल कार्विन

1
हटाए गए Sql-Serverटैग को हटा दिया गया क्योंकि यह संयुक्त टैग खोज पर सर्वोच्च मतदान आइटम था, लेकिन SQL सर्वर के लिए वास्तव में प्रासंगिक नहीं है।
मार्टिन स्मिथ

एक सरल mysql पंक्ति संख्या फ़ंक्शन के लिए, datamakessense.com/mysql-rownum-row-number-function
AdrianBR

MySQL के लिए, केवल कुशल समाधान mysql.rjweb.org/doc.php/groupwise_max में चर्चा की गई है । कई प्रचारित समाधानों के लिए एक पूर्ण तालिका स्कैन (या बदतर) की आवश्यकता होती है।
रिक जेम्स

2
असली विश्लेषणात्मक फ़ंक्शन ROW_NUMBER, RANK, DESNSE_RANK के लिए MySQL में बेशर्मी से स्वयं को बढ़ावा देने वाला समाधान
केनेथ जू

जवाबों:


102

मैं प्रत्येक (col1, col2) जोड़ी के लिए एकल उच्चतम col3 के साथ पंक्ति चाहता हूं।

यह एक समूहवार अधिकतम , सबसे अधिक पूछे जाने वाले एसक्यूएल प्रश्नों में से एक है (क्योंकि ऐसा लगता है कि यह आसान होना चाहिए, लेकिन वास्तव में यह इस तरह का नहीं है)।

मैं अक्सर अशक्त-आत्म-जुड़ाव के लिए विनती करता हूं:

SELECT t0.col3
FROM table AS t0
LEFT JOIN table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3
WHERE t1.col1 IS NULL;

"तालिका में उन पंक्तियों को प्राप्त करें जिनके लिए col1 से मेल खाने वाली कोई अन्य पंक्ति, col2 में एक उच्च col3 है।" (आप इसे नोटिस करेंगे और अधिकांश अन्य समूह-अधिकतम समाधान कई पंक्तियों को वापस कर देंगे यदि एक से अधिक पंक्तियों में एक ही col1, col2, col3 है। यदि यह समस्या है तो आपको कुछ पोस्ट-प्रोसेसिंग की आवश्यकता हो सकती है।)


2
लेकिन क्या होगा अगर एक (col1, col2) जोड़ी के लिए col3 के दो अधिकतम मान हैं? आप दो पंक्तियों के साथ समाप्त करेंगे।
पॉल

@Paul: हाँ! बस इसके बारे में एक नोट जोड़ा कि उत्तर में एक टिक पहले। आप आम तौर पर आसानी से अवांछित अतिरिक्त पंक्तियों अनुप्रयोग परत में बाद में कुछ यादृच्छिक आधार पर ड्रॉप कर सकते हैं, लेकिन यदि आप एक है बहुत यह समस्या हो सकती है एक ही col3 साथ पंक्तियों सब की।
बोबिन्स

1
bobince, समाधान SO पर यहाँ लोकप्रिय हो गया, लेकिन मेरा एक प्रश्न है। समाधान मूल रूप से समान है जैसे कि कोई निम्नलिखित क्वेरी के साथ सबसे बड़ी आईडी खोजने की कोशिश करेगा: SELECT t1.id FROM test t1 LEFT JOIN test t2 ON t1.id>t2.id WHERE t2.id IS NULL;क्या n*n/2 + n/2एकल पंक्ति को खोजने के लिए IS NULL तुलना की आवश्यकता नहीं है? क्या ऐसा कोई अनुकूलन हो सकता है जिसे मैं नहीं देखता? मैंने बिल के समान प्रश्न को एक और सूत्र में रखने की कोशिश की, लेकिन उन्होंने इसे नजरअंदाज कर दिया है।
newtover

2
@Paul - उस मामले को संबोधित करने के लिए जहां कई पंक्तियाँ मौजूद हैं जो प्रति समूह अधिकतम से मेल खाती हैं और आप केवल एक को हथियाना चाहते हैं, आप हमेशा टाई को तोड़ने के लिए ON खंड तर्क में प्राथमिक कुंजी जोड़ सकते हैं ... चयन करें t0.col3 तालिका से AS t0 LEFT JOIN टेबल AS t1 ON t0.col1 = t1.col1 और t0.col2 = t1.col2 AND (t1.col3, t1.pk)> (t0.col3, t0.pk) WHERE t1.col1 IS NULL;
जॉन आर्मस्ट्रांग - Xgc

2
यह अधिक पठनीय होगा जैसे किSELECT t0.col3 FROM table AS t0 WHERE NOT EXISTS (select 1 from table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3)
wrschneider

204

MySQL में कोई रैंकिंग कार्यक्षमता नहीं है। एक चर का उपयोग करने के लिए आपको सबसे करीब मिल सकता है:

SELECT t.*, 
       @rownum := @rownum + 1 AS rank
  FROM YOUR_TABLE t, 
       (SELECT @rownum := 0) r

तो मेरे मामले में यह कैसे काम करेगा? मुझे दो चर की आवश्यकता होगी, प्रत्येक col1 और col2 के लिए एक? जब Col2 बदल गया तब Col2 को किसी तरह रीसेट करने की आवश्यकता होगी ..?

हाँ। यदि यह Oracle था, तो आप LEAD फ़ंक्शन का उपयोग अगले मूल्य पर चोटी पर करने के लिए कर सकते हैं। शुक्र है, क्वासोई शामिल हैं ने MySQL में आपको जो लागू करने की आवश्यकता है उसके लिए तर्क किया है


1
हम्म .... तो मेरे मामले में यह कैसे काम करेगा? मुझे दो चर की आवश्यकता होगी, प्रत्येक col1 और col2 के लिए एक? जब Col2 बदल गया तब Col2 को किसी तरह रीसेट करने की आवश्यकता होगी ..?
पॉल

धन्यवाद ... जैसा कि मैंने ऊपर कहा, यह उत्तर समान रूप से स्वीकार किया जाता है बोबिन्स, लेकिन मैं केवल एक ही टिक कर सकता हूं :-)
पॉल

9
एक ही बयान में उपयोगकर्ता-परिभाषित चर से असाइन करना और पढ़ना विश्वसनीय नहीं है। यह यहाँ प्रलेखित है: dev.mysql.com/doc/refman/5.0/en/user-variables.html : "एक सामान्य नियम के रूप में, आपको कभी भी किसी उपयोगकर्ता चर का मान निर्दिष्ट नहीं करना चाहिए और उसी कथन के भीतर मूल्य पढ़ना चाहिए। आपको वे परिणाम मिल सकते हैं जिनकी आप अपेक्षा करते हैं, लेकिन इसकी गारंटी नहीं है। उपयोगकर्ता चर को शामिल करने वाले अभिव्यक्तियों के मूल्यांकन का क्रम अपरिभाषित है और किसी दिए गए विवरण के भीतर निहित तत्वों के आधार पर बदल सकता है। "
रोलैंड बोमन

1
@ रोलैंड: मैंने केवल छोटे डेटासेट पर परीक्षण किया है, इसमें कोई समस्या नहीं है। बहुत खराब MySQL कार्यक्षमता को संबोधित करने के लिए अभी तक - 2008 के बाद से अनुरोध किया गया है
OMG Ponies

2
यह रोलाण्ड नोट्स के रूप में अपरिभाषित व्यवहार प्रतीत होता है। उदाहरण के लिए, यह मेरे द्वारा SELECT @row_num:=@row_num+1 AS row_number, t.id FROM (SELECT * FROM table1 WHERE col = 264 ORDER BY id) t, (SELECT @row_num:=0) var;
आजमाई

81

मैं हमेशा इस पैटर्न का पालन करता हूं। इस तालिका को देखते हुए:

+------+------+
|    i |    j |
+------+------+
|    1 |   11 |
|    1 |   12 |
|    1 |   13 |
|    2 |   21 |
|    2 |   22 |
|    2 |   23 |
|    3 |   31 |
|    3 |   32 |
|    3 |   33 |
|    4 |   14 |
+------+------+

आप यह परिणाम प्राप्त कर सकते हैं:

+------+------+------------+
|    i |    j | row_number |
+------+------+------------+
|    1 |   11 |          1 |
|    1 |   12 |          2 |
|    1 |   13 |          3 |
|    2 |   21 |          1 |
|    2 |   22 |          2 |
|    2 |   23 |          3 |
|    3 |   31 |          1 |
|    3 |   32 |          2 |
|    3 |   33 |          3 |
|    4 |   14 |          1 |
+------+------+------------+

इस क्वेरी को चलाकर, जिसे परिभाषित किसी चर की आवश्यकता नहीं है:

SELECT a.i, a.j, count(*) as row_number FROM test a
JOIN test b ON a.i = b.i AND a.j >= b.j
GROUP BY a.i, a.j

उम्मीद है की वो मदद करदे!


1
यदि स्तंभ VARCHAR या CHAR हैं, तो आप इस संरचना से कैसे निपट सकते हैं?
तुषार

3
आप भययोग्य हैं Mosty, मैं इसके लिए वास्तव में देख रहा हूँ
luckykrish

बस पंक्ति_number के लिए अपने तर्क का उपयोग करके यह उत्तर दिया । धन्यवाद।
उत्सव

ऑपरेटरों @Tushar <, >, <=, >=संभाल CHAR और वर्णमाला क्रम पर VARCHAR डेटा प्रकार; मुझे उम्मीद है, वास्तव में आप क्या देख रहे हैं।
एलेक्स

1
@AlmazVildanov आप इस क्वेरी का उपयोग केवल एक सबकुछ के लिए फिल्टर के रूप में कर सकते हैं row_numbers <= 2 और इस जवाब के लिए बहुत धन्यवाद, Mosty, यह एकदम सही है!
ज़क्स

61
SELECT 
    @i:=@i+1 AS iterator, 
    t.*
FROM 
    tablename AS t,
    (SELECT @i:=0) AS foo

1
पहला: = लगता है कि @OMG पॉनीज़ उत्तर से गायब है। इस पीटर जॉनसन को पोस्ट करने के लिए धन्यवाद।
शॉल्लिंगिंगर

मुझे लगता है कि (SELECT @i: = 0) AS फू को FROM स्टेटमेंट में पहली तालिका होनी चाहिए, खासकर अगर अन्य तालिकाओं में उप-चयन का उपयोग किया गया हो
andig

आपको 'फू के रूप में' की भी आवश्यकता क्यों है?
टॉम चिवर्टन

@TomChiverton यदि यह गायब है, तो आप प्राप्त करें: "त्रुटि कोड: 1248। प्रत्येक व्युत्पन्न तालिका का अपना उपनाम होना चाहिए"
ExStackChanger

1
यहाँ रैंक असाइनमेंट पूरी तरह से अपरिभाषित है और इस सवाल का जवाब भी नहीं देता है
jberryman

27

इस अनुच्छेद की जाँच करें, यह दिखाता है कि MySQL द्वारा विभाजन के साथ SQL ROW_NUMBER () की नकल कैसे की जाए। मैं एक WordPress कार्यान्वयन में इसी परिदृश्य में भाग गया। मुझे ROW_NUMBER () की आवश्यकता थी और यह वहां नहीं था।

http://www.explodybits.com/2011/11/mysql-row-number/

लेख में उदाहरण क्षेत्र द्वारा एक विभाजन का उपयोग कर रहा है। अतिरिक्त क्षेत्रों द्वारा विभाजन के लिए आप कुछ इस तरह से कर सकते हैं:

  SELECT  @row_num := IF(@prev_value=concat_ws('',t.col1,t.col2),@row_num+1,1) AS RowNumber
         ,t.col1 
         ,t.col2
         ,t.Col3
         ,t.col4
         ,@prev_value := concat_ws('',t.col1,t.col2)
    FROM table1 t,
         (SELECT @row_num := 1) x,
         (SELECT @prev_value := '') y
   ORDER BY t.col1,t.col2,t.col3,t.col4 

Concat_ws का उपयोग करना null का नियंत्रण करता है। मैंने एक इंट, डेट, और वर्चर का उपयोग करके 3 क्षेत्रों के खिलाफ यह परीक्षण किया। उम्मीद है की यह मदद करेगा। लेख को देखें क्योंकि यह इस प्रश्न को तोड़ता है और इसे समझाता है।


1
बहुत बढ़िया। यह वास्तव में विभाजन करता है। बहुत काम
स्टुअर्ट वाट

1
सेल्फ ज्वाइन की तुलना में, यह बहुत अधिक कुशल है, लेकिन तर्क के साथ एक समस्या है, क्रमबद्ध पंक्ति_num से पहले आदेश होना चाहिए, कॉन्कैट भी आवश्यक नहीं है। `` `का चयन करें @row_num: = IF (@ prev_col1 = t.col1 और @ prev_col2 = t.col2), @ row_num + 1, 1) AS RowNumber, t.col1, t.col2, t.col3, t.col4 , @ prev_col1: = t.col1, @ prev_col2: = t.col2 FROM (SELECT * FROM table1 ORDER BY col1, col2, col3) t, (SELECT @row_num = = 1, @ prev_col1: = '', @ prev_col2: = '') var `` `
केनेथ जू

यदि आपको ट्यूव की जरूरत है तो इसे एक उपकुंजी में डाल दें, फिर limit 18446744073709551615बल order byक्लॉज में जोड़ें ।
xmedeko

concat_wsखाली स्ट्रिंग ''खतरनाक है concat_ws('',12,3) = concat_ws('',1,23):। कुछ विभाजक का उपयोग करने '_'या @Kenneth Xu समाधान का उपयोग करने के लिए बेहतर है ।
xmedeko

ऑप का लिंक मृत है; लिंक का संग्रह यहाँ
user2426679

25

से MySQL 8.0.0और इसके बाद के संस्करण आप मूल रूप से विडों कार्यों का उपयोग कर सकते हैं।

1.4 MySQL 8.0 में नया क्या है :

विंडो फ़ंक्शन।

MySQL अब विंडो फ़ंक्शंस का समर्थन करता है जो क्वेरी से प्रत्येक पंक्ति के लिए, उस पंक्ति से संबंधित पंक्तियों का उपयोग करके गणना करता है। इनमें RANK (), LAG (), और NTILE () जैसे फ़ंक्शंस शामिल हैं। इसके अलावा, कई मौजूदा कुल कार्यों को अब विंडो फ़ंक्शन के रूप में उपयोग किया जा सकता है; उदाहरण के लिए, SUM () और AVG ()।

ROW_NUMBER () over_clause :

अपने विभाजन के भीतर वर्तमान पंक्ति की संख्या लौटाता है। पंक्तियों की संख्या 1 से लेकर विभाजन की पंक्तियों तक होती है।

ORDER BY उस क्रम को प्रभावित करता है जिसमें पंक्तियाँ क्रमांकित हैं। ORDER BY के बिना, पंक्ति क्रमांकन अनिश्चित है।

डेमो:

CREATE TABLE Table1(
  id INT AUTO_INCREMENT PRIMARY KEY, col1 INT,col2 INT, col3 TEXT);

INSERT INTO Table1(col1, col2, col3)
VALUES (1,1,'a'),(1,1,'b'),(1,1,'c'),
       (2,1,'x'),(2,1,'y'),(2,2,'z');

SELECT 
    col1, col2,col3,
    ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1;

DBFiddle डेमो


1
आह ... आखिरी में!
प्रयुक्त_By_Already

15

मैं उनके प्रश्न कोड में मामूली संशोधन के साथ Mosty Mostacho के समाधान के लिए भी मतदान करूंगा:

SELECT a.i, a.j, (
    SELECT count(*) from test b where a.j >= b.j AND a.i = b.i
) AS row_number FROM test a

जो एक ही परिणाम देगा:

+------+------+------------+
|    i |    j | row_number |
+------+------+------------+
|    1 |   11 |          1 |
|    1 |   12 |          2 |
|    1 |   13 |          3 |
|    2 |   21 |          1 |
|    2 |   22 |          2 |
|    2 |   23 |          3 |
|    3 |   31 |          1 |
|    3 |   32 |          2 |
|    3 |   33 |          3 |
|    4 |   14 |          1 |
+------+------+------------+

तालिका के लिए:

+------+------+
|    i |    j |
+------+------+
|    1 |   11 |
|    1 |   12 |
|    1 |   13 |
|    2 |   21 |
|    2 |   22 |
|    2 |   23 |
|    3 |   31 |
|    3 |   32 |
|    3 |   33 |
|    4 |   14 |
+------+------+

केवल अंतर के साथ कि क्वेरी JOIN और GROUP BY का उपयोग नहीं करती है, इसके बजाय नेस्टेड चयन पर निर्भर है।


क्या यह बेहतर माना जाता है? वे दोनों द्विघात होने की संभावना रखते हैं, लेकिन मुझे यकीन नहीं है कि EXPLAIN आउटपुट को कैसे इंटरप्रेट करना है
jberryman

वास्तव में, नेस्टेड सेलेक्ट्स को MySQL में बहुत अच्छी तरह से ऑप्टिमाइज़ नहीं किया जाता है, इसलिए यह awser सिर्फ एक क्वेरी तकनीक के प्रदर्शन के लिए है। सबसे व्यावहारिक मामलों के लिए बेहतर काम करने के लिए ऊपर दिए गए चर-आधारित उदाहरण, मुझे लगता है।
abcdn

1
मुझे विश्वास नहीं है कि चर आधारित उत्तर में से कोई भी वास्तव में परिभाषित व्यवहार का उपयोग कर रहा है ...
jberryman

मुझे खेद है, मुझे यकीन नहीं है कि मुझे "परिभाषित व्यवहार" से आपका मतलब है। क्या इसका मतलब यह है कि यह आपके लिए काम नहीं करता है, या आप बस चिंतित हैं कि यह दस्तावेज नहीं है?
abcdn

1
"अपरिभाषित व्यवहार" का अर्थ है कि यह काम करने के लिए प्रलेखित नहीं है और / या काम करने की गारंटी नहीं होने के लिए प्रलेखित है। इस पृष्ठ पर टिप्पणियों में प्रलेखन उद्धरण और लिंक देखें। यह वही हो सकता है जो एक (निराधार) चाहता है / अनुमान / परिकल्पना / कल्पना करता है। कार्यान्वयन के कुछ संस्करणों के लिए CASE इंक्रीमेंट और वेरिएबल्स का उपयोग करके कुछ क्वेरी एक्सप्रेशंस को प्रोग्रामर द्वारा Percona में कोड को देखकर काम करने के लिए दिखाया गया है। यह किसी भी रिलीज के साथ बदल सकता है।
फिलीपींस

12

मैं एक समारोह को परिभाषित करेगा:

delimiter $$
DROP FUNCTION IF EXISTS `getFakeId`$$
CREATE FUNCTION `getFakeId`() RETURNS int(11)
    DETERMINISTIC
begin
return if(@fakeId, @fakeId:=@fakeId+1, @fakeId:=1);
end$$

तब मैं कर सकता था:

select getFakeId() as id, t.* from table t, (select @fakeId:=0) as t2;

अब आपके पास एक उपश्रेणी नहीं है, जिसे आप देख नहीं सकते।


एक सीमा के साथ काम करता है: यदि आप क्वेरी को कई बार निष्पादित करते हैं, तो आपको एक ही परिणाम सेट के लिए कभी-कभी बढ़ते हुए फ़र्ज़ी मिलेंगे
Stephan Richter

आप @fakeId = 0 सेट भेज सकते हैं; हर बार जब आप क्वेरी चलाना चाहते हैं, तो इष्टतम नहीं है, लेकिन काम करता है
jpeace

यदि आप DETERMINISTIC को हटा दें तो वास्तव में एक अजीब समस्या होती है। तब आदेश का उपयोग करते समय फर्जी आई डी गलत है। ऐसा क्यों है?
क्रिस मुयंच

8

mysql में row_number के लिए क्वेरी

set @row_number=0;
select (@row_number := @row_number +1) as num,id,name from sbs

इसका उपयोग UPDATE प्रश्नों पर किया जा सकता है? मैं कोशिश कर रहा हूं, लेकिन मुझे "कॉलम के लिए डेटा काट दिया गया ..." त्रुटि मिली।
डिएगो

1
यदि किसी को UPDATE पर इसका उपयोग करने में रुचि है, तो उसे काम करने के लिए उप-क्वेरी के रूप में उपयोग किया जाना चाहिए। अद्यतन करें <तालिका> सेट <फ़ील्ड> = (Select \ @row_number: = \ @row_number +1) आदेश द्वारा <अपने आदेश कॉलम>; ऑर्डर कॉलम पंक्तियों के मूल्य क्रम को निर्धारित करता है।
डिएगो

8

MySQL में कोई funtion की तरह नहीं है rownum, row_num()लेकिन चारों ओर का रास्ता नीचे की तरह है:

select 
      @s:=@s+1 serial_no, 
      tbl.* 
from my_table tbl, (select @s:=0) as s;

4

सबसे अच्छा काम करने के लिए मैंने जो समाधान पाया, वह इस तरह से एक उपश्रेणी का उपयोग कर रहा था:

SELECT 
    col1, col2, 
    (
        SELECT COUNT(*) 
        FROM Table1
        WHERE col1 = t1.col1
        AND col2 = t1.col2
        AND col3 > t1.col3
    ) AS intRow
FROM Table1 t1

कॉलम बाय पार्टिशन सिर्फ '=' के साथ तुलना करके और से अलग हो जाता है। ORDER BY कॉलम की तुलना '<' या '>' से की जाएगी, और OR द्वारा अलग किया जाएगा।

मैंने इसे बहुत लचीला पाया है, भले ही यह थोड़ा महंगा हो।


4

रोन्नंबर कार्यक्षमता की नकल नहीं की जा सकती। आपको वे परिणाम मिल सकते हैं जिनकी आप उम्मीद करते हैं, लेकिन आपको सबसे अधिक संभावना है कि आप किसी चरण में निराश होंगे। यहाँ है mysql प्रलेखन क्या कहता है:

अन्य बयानों के लिए, जैसे कि SELECT, आपको अपेक्षित परिणाम मिल सकते हैं, लेकिन इसकी गारंटी नहीं है। निम्नलिखित कथन में, आप सोच सकते हैं कि MySQL पहले @a का मूल्यांकन करेगा और फिर एक असाइनमेंट दूसरा करेगा: SELECT @a, @a: = @ a + 1, ...; हालाँकि, उपयोगकर्ता चर शामिल अभिव्यक्तियों के लिए मूल्यांकन का क्रम अपरिभाषित है।

सादर, जॉर्जी


मैं अनुसरण नहीं करता। स्थिति के रूप में "@i: = @i + 1" स्थिति के रूप में "ROW_NUMBER () ओवर (ऑर्डर द्वारा राशि (स्कोर) desc) के लिए प्रत्यक्ष प्रतिस्थापन नहीं है" कैसे है?
टॉम चिवर्टन

1
@TomChiverton क्योंकि इसका व्यवहार परिभाषित नहीं है, क्योंकि मैनुअल वहीं कहता है।
फिलिप जू

4

MariaDB 10.2 "विंडो फ़ंक्शंस" को लागू कर रही है, जिसमें RANK (), ROW_NUMBER () और कई अन्य चीज़ें शामिल हैं:

https://mariadb.com/kb/en/mariadb/window-functions/

इस महीने पेरकोना लाइव में एक बात के आधार पर, वे यथोचित रूप से अनुकूलित हैं।

वाक्यविन्यास प्रश्न में कोड के समान है।


2

मुझे यहां "भाग द्वारा" भाग को कवर करने वाला कोई सरल उत्तर नहीं दिखता है, इसलिए यहां मेरा है:

SELECT
    *
FROM (
    select
        CASE WHEN @partitionBy_1 = l THEN @row_number:=@row_number+1 ELSE @row_number:=1 END AS i
        , @partitionBy_1:=l AS p
        , t.*
    from (
        select @row_number:=0,@partitionBy_1:=null
    ) as x
    cross join (
        select 1 as n, 'a' as l
        union all
        select 1 as n, 'b' as l    
        union all
        select 2 as n, 'b' as l    
        union all
        select 2 as n, 'a' as l
        union all
        select 3 as n, 'a' as l    
        union all    
        select 3 as n, 'b' as l    
    ) as t
    ORDER BY l, n
) AS X
where i > 1
  • ORDER BY क्लॉज को आपकी ROW_NUMBER की आवश्यकता को प्रतिबिंबित करना चाहिए। इस प्रकार पहले से ही एक स्पष्ट सीमा है: आप एक ही समय में इस फॉर्म के कई ROW_NUMBER "अनुकरण" नहीं कर सकते।
  • "कंप्यूटेड कॉलम" का क्रम मायने रखता है । यदि आपके पास mysql किसी अन्य क्रम में उन कॉलम की गणना करता है, तो यह काम नहीं कर सकता है।
  • इस सरल उदाहरण में मैंने केवल एक ही डाला है, लेकिन आपके पास कई "पार्टिशन बाय" भाग हो सकते हैं

        CASE WHEN @partitionBy_1 = part1 AND @partitionBy_2 = part2 [...] THEN @row_number:=@row_number+1 ELSE @row_number:=1 END AS i
        , @partitionBy_1:=part1 AS P1
        , @partitionBy_2:=part2 AS P2
        [...] 
    FROM (
        SELECT @row_number:=0,@partitionBy_1:=null,@partitionBy_2:=null[...]
    ) as x

1

थोड़ा देर से लेकिन किसी ऐसे व्यक्ति की मदद भी कर सकता है जो उत्तर की तलाश में है ...

पंक्तियों / row_number उदाहरण के बीच - पुनरावर्ती क्वेरी जो किसी SQL में उपयोग की जा सकती है:

WITH data(row_num, some_val) AS 
(
 SELECT 1 row_num, 1 some_val FROM any_table --dual in Oracle
  UNION ALL
 SELECT row_num+1, some_val+row_num FROM data WHERE row_num < 20 -- any number
)
SELECT * FROM data
 WHERE row_num BETWEEN 5 AND 10
/

ROW_NUM    SOME_VAL
-------------------
5           11
6           16
7           22
8           29
9           37
10          46

2
क्षमा करें, लेकिन जहाँ तक मुझे पता है कि MySQL आम तालिका अभिव्यक्तियों का समर्थन नहीं करता है ।
अल्वारो गोंजालेज

यह अब ... @ rolvaroGonzález MySQL 8 केवल CTE और विंडो फ़ंक्शंस का समर्थन करता है, इसलिए यह उत्तर वास्तव में पुराने MySQL संस्करणों में उपयोग करने के लिए समझ में नहीं आता है ..
रेमंड निज़लैंड

1

यह उसी कार्यक्षमता को अनुमति देता है जो ROW_NUMBER () और विभाजन बाय द्वारा MySQL में प्राप्त करने के लिए प्रदान करता है

SELECT  @row_num := IF(@prev_value=GENDER,@row_num+1,1) AS RowNumber
       FirstName, 
       Age,
       Gender,
       @prev_value := GENDER
  FROM Person,
      (SELECT @row_num := 1) x,
      (SELECT @prev_value := '') y
  ORDER BY Gender, Age DESC

1

थोड़ा और देर से, लेकिन आज मुझे वही ज़रूरत थी इसलिए मैंने Google पर खोज की और अंत में यहाँ एक साधारण सामान्य दृष्टिकोण पाया जो कि पिनाल डेव के लेख में है। http://blog.sqlauthority.com/2014/03/09/mysql-reset-row -number के लिए प्रत्येक समूह-विभाजन-दर-पंक्ति-संख्या /

मैं पॉल के मूल प्रश्न (जो मेरी समस्या भी थी) पर ध्यान केंद्रित करना चाहता था, इसलिए मैं एक समाधान के रूप में अपने समाधान को संक्षेप में प्रस्तुत करता हूं।

यदि हम एक नया समूह शुरू किया गया था, तो पहचानने के दौरान हम दो कॉलम पर विभाजन करना चाहते हैं, ताकि मैं एक SET चर बना सकूं।

SELECT col1, col2, col3 FROM (
  SELECT col1, col2, col3,
         @n := CASE WHEN @v = MAKE_SET(3, col1, col2)
                    THEN @n + 1 -- if we are in the same group
                    ELSE 1 -- next group starts so we reset the counter
                END AS row_number,
         @v := MAKE_SET(3, col1, col2) -- we store the current value for next iteration
    FROM Table1, (SELECT @n := 0, @v := NULL) r -- helper table for iteration with startup values
   ORDER BY col1, col2, col3 DESC -- because we want the row with maximum value
) x WHERE row_number = 1 -- and here we select exactly the wanted row from each group

MAKE_SET के पहले पैरामीटर पर 3 का मतलब है कि मैं दोनों मूल्य SET (3 = 1 | 2) चाहता हूं। बेशक अगर हमारे पास दो या दो से अधिक कॉलम नहीं हैं, तो हम उन समूहों का निर्माण कर सकते हैं जिन्हें हम MAKE_SET ऑपरेशन को समाप्त कर सकते हैं। निर्माण बिलकुल एक जैसा है। यह आवश्यकतानुसार मेरे लिए काम कर रहा है। पिनाल डेव को उनके स्पष्ट प्रदर्शन के लिए बहुत धन्यवाद।


1
ध्यान दें कि ORDER BYएक सबकुछ को नजरअंदाज किया जा सकता है (देखें mariadb.com/kb/en/mariadb/… )। उस के लिए सुझाए गए समाधान को LIMIT 18446744073709551615उप-वर्ग में जोड़ना है, जो एक प्रकार को बाध्य करता है। हालांकि यह प्रदर्शन के मुद्दों का कारण बन सकता है और वास्तव में
प्रचंड

1

यह भी एक समाधान हो सकता है:

SET @row_number = 0;

SELECT 
    (@row_number:=@row_number + 1) AS num, firstName, lastName
FROM
    employees

हालांकि यह कोई विभाजन नहीं करता है, और यह एक उच्च उद्धृत उत्तर के लिए काफी अलग नहीं है
कायुस जार्ड

1

MySQL ने संस्करण 8.0+ के बाद से ROW_NUMBER () का समर्थन किया है

यदि आप MySQL 8.0 या बाद के संस्करण का उपयोग करते हैं, तो इसे ROW_NUMBER () फ़ंक्शन देखें। अन्यथा, आपने ROW_NUMBER () फ़ंक्शन का अनुकरण किया है।

Row_number () एक रैंकिंग फ़ंक्शन है जो पहली पंक्ति के लिए 1 से शुरू होकर पंक्ति की क्रमिक संख्या देता है।

पुराने संस्करण के लिए,

SELECT t.*, 
       @rowid := @rowid + 1 AS ROWID
  FROM TABLE t, 
       (SELECT @rowid := 0) dummy;

1

महत्वपूर्ण: कृपया MySQL 8+ में अपग्रेड करने पर विचार करें और परिभाषित और प्रलेखित ROW_NUMBER () फ़ंक्शन का उपयोग करें, और MySQL के प्राचीन संस्करण तक सीमित फीचर से बंधे पुराने हैक को खोदें

अब यहाँ उन हैक्स में से एक है:

इन-क्वेरी चर का उपयोग करने वाले उत्तर यहां ज्यादातर / सभी इस तथ्य को अनदेखा करते दिखते हैं कि दस्तावेज़ीकरण कहता है (paraphrase):

ऊपर से नीचे तक के क्रम में मूल्यांकन की जा रही चयन सूची में वस्तुओं पर भरोसा न करें। एक सेलेक्ट आइटम में वैरिएबल असाइन न करें और उन्हें दूसरे में उपयोग करें

इस प्रकार, वहाँ एक जोखिम है जो वे गलत उत्तर का मंथन करेंगे, क्योंकि वे आम तौर पर ए

select
  (row number variable that uses partition variable),
  (assign partition variable)

यदि इनका मूल्यांकन नीचे किया जाता है, तो पंक्ति संख्या काम करना बंद कर देगी (विभाजन नहीं)

इसलिए हमें निष्पादन की गारंटी के साथ कुछ का उपयोग करने की आवश्यकता है। मामला दर्ज करें:

SELECT
  t.*, 
  @r := CASE 
    WHEN col = @prevcol THEN @r + 1 
    WHEN (@prevcol := col) = null THEN null
    ELSE 1 END AS rn
FROM
  t, 
  (SELECT @r := 0, @prevcol := null) x
ORDER BY col

जैसा कि रूपरेखा ld, prevcol के असाइनमेंट का क्रम महत्वपूर्ण है - मौजूदा रो की मौजूदा पंक्ति के मूल्य से तुलना की जानी चाहिए, इससे पहले कि हम इसे वर्तमान पंक्ति से एक मान असाइन करें (अन्यथा यह मौजूदा पंक्तियों का कॉल मान होगा, न कि पिछली पंक्ति का कॉल मान) ।

यहां बताया गया है कि यह एक साथ कैसे फिट होता है:

  • पहले WHEN का मूल्यांकन किया जाता है। यदि इस पंक्ति का कर्नल पिछली पंक्ति के कॉल के समान है तो @r वृद्ध हो जाता है और CASE से वापस आ जाता है। यह रिटर्न लीड मान @r में संग्रहीत है। यह MySQL की एक विशेषता है जो असाइनमेंट परिणाम पंक्तियों में @r में दिए गए नए मान को लौटाता है।

  • परिणाम सेट पर पहली पंक्ति के लिए, @prevcol अशक्त है (यह उपनगरीय क्षेत्र में नल के लिए आरम्भिक है) इसलिए यह विधेय गलत है। यह पहला विधेय भी हर बार कर्नल परिवर्तन (वर्तमान पंक्ति पिछली पंक्ति के लिए अलग है) गलत देता है। इसके कारण दूसरे WHEN का मूल्यांकन किया जाता है।

  • दूसरा जब विधेय हमेशा गलत होता है, और यह @prevcol को एक नया मान प्रदान करने के लिए विशुद्ध रूप से मौजूद होता है। क्योंकि यह पंक्ति का कर्नल पिछली पंक्ति के कर्नल से भिन्न है (हम इसे जानते हैं क्योंकि यदि यह समान होता, तो पहले WHEN का उपयोग किया गया होता), हमें इसे अगली बार परीक्षण के लिए रखने के लिए नया मान असाइन करना होगा। क्योंकि असाइनमेंट बनाया गया है और फिर असाइनमेंट के परिणाम की तुलना नल के साथ की जाती है, और अशक्त के बराबर कुछ भी गलत है, यह विधेय हमेशा गलत होता है। लेकिन कम से कम इसका मूल्यांकन करने वाले ने इस पंक्ति से कॉल के मूल्य को रखने का अपना काम किया, इसलिए इसका मूल्यांकन अगली पंक्ति के कॉल वैल्यू के खिलाफ किया जा सकता है

  • क्योंकि दूसरा WHEN झूठा है, इसका मतलब उन परिस्थितियों में है, जहां हम (col) विभाजन कर रहे कॉलम को बदल दिया है, यह ELSE है जो @r के लिए एक नया मान देता है, क्रमांक 1 से पुनः आरंभ

हम इसे ऐसी स्थिति में ले जाते हैं जहाँ:

SELECT
  t.*, 
  ROW_NUMBER() OVER(PARTITION BY pcol1, pcol2, ... pcolX ORDER BY ocol1, ocol2, ... ocolX) rn
FROM
  t

सामान्य रूप है:

SELECT
  t.*, 
  @r := CASE 
    WHEN col1 = @pcol1 AND col2 = @pcol2 AND ... AND colX = @pcolX THEN @r + 1 
    WHEN (@pcol1 := pcol1) = null OR (@pcol2 := col2) = null OR ... OR (@pcolX := colX) = null THEN null
    ELSE 1 
  END AS rn
FROM
  t, 
  (SELECT @r := 0, @pcol1 := null, @pcol2 := null, ..., @pcolX := null) x
ORDER BY pcol1, pcol2, ..., pcolX, ocol1, ocol2, ..., ocolX

फुटनोट:

  • पीसीओल में पी का अर्थ है "विभाजन", ओ में चॉकलेट का अर्थ है "आदेश" - सामान्य रूप में मैंने दृश्य अव्यवस्था को कम करने के लिए चर नाम से "प्रचलित" को गिरा दिया

  • चारों ओर के कोष्ठक (@pcolX := colX) = nullमहत्वपूर्ण हैं। उनके बिना आप @pcolX को अशक्त कर देंगे और चीजें काम करना बंद कर देंगी

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

  • मैंने यह परीक्षण करने से परे विलम्ब नहीं किया है कि विधि काम करती है, लेकिन अगर कोई जोखिम है कि दूसरी WHEN में विधेय को कहां से अनुकूलित किया जाएगा (अशक्त की तुलना में कुछ भी अशक्त / गलत है तो असाइनमेंट चलाने में परेशान क्यों हों) और निष्पादित नहीं किया गया , यह भी बंद हो जाता है। यह मेरे अनुभव में नहीं लगता है, लेकिन मैं ख़ुशी से टिप्पणियों को स्वीकार करूंगा और समाधान का प्रस्ताव कर सकता हूं यदि यह यथोचित रूप से हो सकता है

  • हो सकता है कि आपके स्तंभों के वास्तविक प्रकारों में @pcolX बनाने वाले नलियों को, उप-वर्ग में, जो @pcolX चर बनाता है, अर्थात: select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)


इसका कोई औचित्य नहीं है। ठीक उसी तरह जैसे दूसरे उत्तर जो एक ही चर से पढ़ते और पढ़ते हैं।
फिलिप

क्या आप अधिक विस्तार फिल की आपूर्ति कर सकते हैं?
कायुस जार्ड

इस पृष्ठ पर मेरी अन्य टिप्पणियाँ देखें। Googling 'साइट: stackoverflow.com "myipqxy" mysql वैरिएबल (सेट या असाइन या असाइनमेंट या राइट) पढ़ें': मेरे द्वारा दिए गए एक उत्तर और इस सवाल पर मेरे द्वारा टिप्पणी में जुड़ी एक बग रिपोर्ट जहां स्वीकृत उत्तर मैनुअल को तुरंत उद्धृत करता है। दावों में इसके विपरीत कुछ करना ठीक है। मैनुअल री वैरिएबल और पुन: असाइनमेंट पढ़ें।
फिलीपिक्‍स


मैं आपकी चिंता को समझता हूं
कायुस जार्ड

0

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

कुछ इस तरह से मेरे लिए अतीत में काम किया है:

SELECT t.*, 
   CASE WHEN <partition_field> = @rownum1 := @rownum1 + 1 
     WHEN <partition_field> = @rownum2 := @rownum2 + 1 
     ...
     END AS rank
FROM YOUR_TABLE t, 
   (SELECT @rownum1 := 0) r1, (SELECT @rownum2 := 0) r2
ORDER BY <rank_order_by_field>
;

आशा है कि समझ में आता है / मदद करता है!


-1

जब हम एक से अधिक कॉलम रखते हैं तो रोवनंबर बनाने के लिए यह पूरी तरह से मेरे लिए काम करते हैं। इस मामले में दो कॉलम।

SELECT @row_num := IF(@prev_value= concat(`Fk_Business_Unit_Code`,`NetIQ_Job_Code`), @row_num+1, 1) AS RowNumber, 
    `Fk_Business_Unit_Code`,   
    `NetIQ_Job_Code`,  
    `Supervisor_Name`,  
    @prev_value := concat(`Fk_Business_Unit_Code`,`NetIQ_Job_Code`)  
FROM (SELECT DISTINCT `Fk_Business_Unit_Code`,`NetIQ_Job_Code`,`Supervisor_Name`         
      FROM Employee    
      ORDER BY `Fk_Business_Unit_Code`, `NetIQ_Job_Code`, `Supervisor_Name` DESC) z,  
(SELECT @row_num := 1) x,  
(SELECT @prev_value := '') y  
ORDER BY `Fk_Business_Unit_Code`, `NetIQ_Job_Code`,`Supervisor_Name` DESC

-3
set @i = 1;  
INSERT INTO ARG_VALUE_LOOKUP(ARG_VALUE_LOOKUP_ID,ARGUMENT_NAME,VALUE,DESCRIPTION,UPDATE_TIMESTAMP,UPDATE_USER,VER_NBR,OBJ_ID) 
select @i:= @i+1 as ARG_VALUE_LOOKUP_ID,ARGUMENT_NAME,VALUE,DESCRIPTION,CURRENT_TIMESTAMP,'admin',1,UUID() 
FROM TEMP_ARG_VALUE_LOOKUP 
order by ARGUMENT_NAME;

1
कृपया किसी भी उत्तर को प्रारूपित करने का प्रयास करें और कुछ अतिरिक्त संदर्भ दें जो आप करने की कोशिश कर रहे हैं। फिलहाल यह और कुछ नहीं बल्कि खराब स्वरूपित पाठ है।
यानिक मीस

2
यह मूल प्रश्न का कोई संबंध नहीं है। यदि आपका स्वयं का प्रश्न है, तो कृपया इसे अलग से पूछें।
जेरोइन मोस्टर्ट

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