MySQL में प्राकृतिक सॉर्ट


81

क्या MySQL डेटाबेस में परफ़ॉर्मेंट, नेचुरल सॉर्टिंग करने का एक सुंदर तरीका है?

उदाहरण के लिए यदि मेरे पास यह डेटा सेट है:

  • अंतिम ख्वाब
  • अंतिम काल्पनिक 4
  • अंतिम काल्पनिक 10
  • अंतिम काल्पनिक 12
  • अंतिम काल्पनिक 12: चैन ऑफ प्रोमथिया
  • अंतिम काल्पनिक साहसिक
  • अंतिम काल्पनिक उत्पत्ति
  • अंतिम काल्पनिक रणनीति

उनके घटकों में गेम के नामों को विभाजित करने की तुलना में कोई अन्य सुरुचिपूर्ण समाधान

  • शीर्षक : "अंतिम काल्पनिक"
  • संख्या : "12"
  • उपशीर्षक : "चेन ऑफ़ प्रोमथिया"

यह सुनिश्चित करने के लिए कि वे सही क्रम में बाहर आते हैं? (10 के बाद 4, 2 से पहले नहीं)।

ऐसा करने से एक ** में दर्द होता है क्योंकि हर अब और फिर एक और गेम है जो गेम टाइटल को पार्स करने के उस तंत्र को तोड़ता है (जैसे "वॉरहैमर 40,000", "जेम्स बॉन्ड 007")


28
Promathia की चेन 11. से संबंधित है
लौ


जवाबों:


20

मुझे लगता है कि इसीलिए बहुत सारी चीजें रिलीज डेट से हल हो जाती हैं।

एक समाधान "SortKey" के लिए अपनी तालिका में एक और कॉलम बनाने के लिए हो सकता है। यह शीर्षक का एक सैनिटाइज्ड संस्करण हो सकता है जो आपके द्वारा आसान छंटाई या काउंटर के लिए बनाए गए पैटर्न के अनुरूप होता है।


मैंने अभी-अभी एक कक्षा के लिए लिखा है कि stackoverflow.com/a/47522040/935122
क्रिश्चियन

2
यह निश्चित रूप से सही दृष्टिकोण है, लेकिन शायद ही अपने आप में एक जवाब है!
चल रहा

90

यहाँ एक त्वरित समाधान है:

SELECT alphanumeric, 
       integer
FROM sorting_test
ORDER BY LENGTH(alphanumeric), alphanumeric

49
यह अच्छा है अगर सब कुछ "अंतिम काल्पनिक" है, लेकिन यह एफएफ सूट के आगे "नासमझ" डालता है।
किलाबीज

4
यह समाधान हर समय काम नहीं करता है। यह कभी-कभी टूट जाता है। आपको इसके बजाय इसका उपयोग करना चाहिए: stackoverflow.com/a/12257917/384864
बोरुत तोमाज़िन

6
क्लिंगिंग पर कीलिंग पाइल SELECT alphanumeric, integer FROM sorting_test ORDER BY SOUNDEX(alphanumeric), LENGTH(alphanumeric), alphanumeric:। यदि यह बिल्कुल काम करता है, तो यह इसलिए है क्योंकि SOUNDEX आसानी से संख्याओं को त्याग देता है, इस प्रकार यह सुनिश्चित करता है कि उदाहरण apple1पहले आता है z1
offby1

महान समाधान, धन्यवाद, हालांकि मुझे "अंतिम काल्पनिक" से पहले "नासमझ" से बचने के लिए स्विच करना पड़ा alphanmuric,length(alphanumeric)
एस्पर्ट

1
@ offby1 सुझाव केवल तभी काम करता है जब पाठ अंग्रेजी में लिखा हुआ 100% हो, जैसा SOUNDEX()कि केवल अंग्रेजी शब्दों पर सही ढंग से काम करने के लिए बनाया गया है।
रेमंड निजलैंड

56

बस यह मिला:

SELECT names FROM your_table ORDER BY games + 0 ASC

जब संख्या सामने होती है, तो एक प्राकृतिक प्रकार होता है, मध्य के लिए भी काम कर सकता है।


2
मैंने इसकी कोशिश नहीं की है, लेकिन मैं गंभीरता से इस पर संदेह करता हूं। कारण यह सामने की संख्या के साथ काम करता है क्योंकि gamesएक संख्यात्मक संदर्भ में के रूप में प्रयोग किया जाता है और इस तरह तुलना करने से पहले एक संख्या में परिवर्तित हो जाता है। यदि बीच में यह हमेशा 0 में बदल जाएगा और छँटाई छद्म यादृच्छिक हो जाएगा।
manixrock

1
यह प्राकृतिक प्रकार नहीं है। इस काम के समाधान पर एक नज़र डालें: stackoverflow.com/a/12257917/384864
बोरुत तोमाजिन

@fedir इसने मेरे लिए भी अच्छा काम किया। मुझे पूरी तरह से यकीन भी नहीं है कि यह क्यों काम करता है। स्पष्टीकरण मार्कशीट का कोई मौका?
बिज़्यूगन

बस इसकी एक त्वरित जांच थी और मैं इसे प्राप्त करता हूं। मुझे एहसास भी नहीं था कि MySQL एक स्ट्रिंग पर गणितीय ऑपरेटर का उपयोग करके इस तरह की कास्टिंग करेगा! ठंडी बात यह है कि यह सिर्फ "कास्ट" स्ट्रिंग के सामने कोई पूर्णांक नहीं होने की स्थिति में zer0 देता है। इसके लिए धन्यवाद! ---> परिसर से चुनें (ADDRESS * 1), जहां से परिसर से बाहर निकलें, जहां पोस्ट 'NE1%' आदेश के अनुसार * 1 ASC, ADDRESS सीमा 100000;
बिज़्यूगन

1
यह वास्तव में तब काम नहीं करता है जब संख्याएं "अंतिम काल्पनिक 100" या "अंतिम काल्पनिक 2" जैसे मध्य में होती हैं। "फाइनल फंतासी 100" पहले दिखाएगी। यह तब भी काम करता है जब पूर्णांक "100 अंतिम काल्पनिक" है
dwenaus

52

समान कार्य @plalx द्वारा पोस्ट किया गया, लेकिन MySQL में फिर से लिखा गया:

DROP FUNCTION IF EXISTS `udf_FirstNumberPos`;
DELIMITER ;;
CREATE FUNCTION `udf_FirstNumberPos` (`instring` varchar(4000)) 
RETURNS int
LANGUAGE SQL
DETERMINISTIC
NO SQL
SQL SECURITY INVOKER
BEGIN
    DECLARE position int;
    DECLARE tmp_position int;
    SET position = 5000;
    SET tmp_position = LOCATE('0', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF; 
    SET tmp_position = LOCATE('1', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF;
    SET tmp_position = LOCATE('2', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF;
    SET tmp_position = LOCATE('3', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF;
    SET tmp_position = LOCATE('4', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF;
    SET tmp_position = LOCATE('5', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF;
    SET tmp_position = LOCATE('6', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF;
    SET tmp_position = LOCATE('7', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF;
    SET tmp_position = LOCATE('8', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF;
    SET tmp_position = LOCATE('9', instring); IF (tmp_position > 0 AND tmp_position < position) THEN SET position = tmp_position; END IF;

    IF (position = 5000) THEN RETURN 0; END IF;
    RETURN position;
END
;;

DROP FUNCTION IF EXISTS `udf_NaturalSortFormat`;
DELIMITER ;;
CREATE FUNCTION `udf_NaturalSortFormat` (`instring` varchar(4000), `numberLength` int, `sameOrderChars` char(50)) 
RETURNS varchar(4000)
LANGUAGE SQL
DETERMINISTIC
NO SQL
SQL SECURITY INVOKER
BEGIN
    DECLARE sortString varchar(4000);
    DECLARE numStartIndex int;
    DECLARE numEndIndex int;
    DECLARE padLength int;
    DECLARE totalPadLength int;
    DECLARE i int;
    DECLARE sameOrderCharsLen int;

    SET totalPadLength = 0;
    SET instring = TRIM(instring);
    SET sortString = instring;
    SET numStartIndex = udf_FirstNumberPos(instring);
    SET numEndIndex = 0;
    SET i = 1;
    SET sameOrderCharsLen = CHAR_LENGTH(sameOrderChars);

    WHILE (i <= sameOrderCharsLen) DO
        SET sortString = REPLACE(sortString, SUBSTRING(sameOrderChars, i, 1), ' ');
        SET i = i + 1;
    END WHILE;

    WHILE (numStartIndex <> 0) DO
        SET numStartIndex = numStartIndex + numEndIndex;
        SET numEndIndex = numStartIndex;

        WHILE (udf_FirstNumberPos(SUBSTRING(instring, numEndIndex, 1)) = 1) DO
            SET numEndIndex = numEndIndex + 1;
        END WHILE;

        SET numEndIndex = numEndIndex - 1;

        SET padLength = numberLength - (numEndIndex + 1 - numStartIndex);

        IF padLength < 0 THEN
            SET padLength = 0;
        END IF;

        SET sortString = INSERT(sortString, numStartIndex + totalPadLength, 0, REPEAT('0', padLength));

        SET totalPadLength = totalPadLength + padLength;
        SET numStartIndex = udf_FirstNumberPos(RIGHT(instring, CHAR_LENGTH(instring) - numEndIndex));
    END WHILE;

    RETURN sortString;
END
;;

उपयोग:

SELECT name FROM products ORDER BY udf_NaturalSortFormat(name, 10, ".")

5
यह एकमात्र समाधान है जो वास्तव में काम करता है। मैंने ड्रुपल कोड का भी परीक्षण किया है लेकिन यह कभी-कभी विफल हो जाता है। धन्यवाद दोस्त!
बोरुत तोमाजिन

किसी को भी वास्तव में बड़े तालिकाओं पर 10+ मिलियन का उपयोग करें?
मार्क स्टुडेल

3
@MarkSteudel हम कई तालिकाओं पर प्राकृतिक छंटाई के लिए इस (हालांकि यह सटीक नहीं है) के समान एक फ़ंक्शन का उपयोग करते हैं, जिनमें से सबसे बड़ी ~ 5 मिलियन पंक्तियाँ हैं। हालाँकि, हम इसे सीधे अपने प्रश्नों में नहीं कहते हैं, बल्कि इसका उपयोग किसी nat_nameकॉलम के मान को सेट करने के लिए करते हैं । हम हर बार एक पंक्ति को अद्यतन करने के लिए एक ट्रिगर का उपयोग करते हैं। यह दृष्टिकोण आपको अतिरिक्त कॉलम की कीमत पर वास्तविक प्रदर्शन लागत के साथ प्राकृतिक छँटाई देता है।
याकूब

यह काम करता है, अक्षरों से पहले संख्याओं को छांटना, और ड्रुपल में hook_views_query_alter का उपयोग करके लागू किया जा सकता है, इस के लिए कुछ का उपयोग करते हुएif ($query->orderby[0]["field"] === "node_field_data.title") { $orderBySql = " udf_NaturalSortFormat(node_field_data.title, 10, '.') "; $query->orderby = []; $query->addOrderBy(NULL, $orderBySql, $query->orderby[0]["direction"], 'title_natural'); array_unshift($query->orderby, end($query->orderby)); }
realgt

16

मैंने कुछ समय पहले MSSQL 2000 के लिए यह फ़ंक्शन लिखा है :

/**
 * Returns a string formatted for natural sorting. This function is very useful when having to sort alpha-numeric strings.
 *
 * @author Alexandre Potvin Latreille (plalx)
 * @param {nvarchar(4000)} string The formatted string.
 * @param {int} numberLength The length each number should have (including padding). This should be the length of the longest number. Defaults to 10.
 * @param {char(50)} sameOrderChars A list of characters that should have the same order. Ex: '.-/'. Defaults to empty string.
 *
 * @return {nvarchar(4000)} A string for natural sorting.
 * Example of use: 
 * 
 *      SELECT Name FROM TableA ORDER BY Name
 *  TableA (unordered)              TableA (ordered)
 *  ------------                    ------------
 *  ID  Name                    ID  Name
 *  1.  A1.                 1.  A1-1.       
 *  2.  A1-1.                   2.  A1.
 *  3.  R1      -->         3.  R1
 *  4.  R11                 4.  R11
 *  5.  R2                  5.  R2
 *
 *  
 *  As we can see, humans would expect A1., A1-1., R1, R2, R11 but that's not how SQL is sorting it.
 *  We can use this function to fix this.
 *
 *      SELECT Name FROM TableA ORDER BY dbo.udf_NaturalSortFormat(Name, default, '.-')
 *  TableA (unordered)              TableA (ordered)
 *  ------------                    ------------
 *  ID  Name                    ID  Name
 *  1.  A1.                 1.  A1.     
 *  2.  A1-1.                   2.  A1-1.
 *  3.  R1      -->         3.  R1
 *  4.  R11                 4.  R2
 *  5.  R2                  5.  R11
 */
CREATE FUNCTION dbo.udf_NaturalSortFormat(
    @string nvarchar(4000),
    @numberLength int = 10,
    @sameOrderChars char(50) = ''
)
RETURNS varchar(4000)
AS
BEGIN
    DECLARE @sortString varchar(4000),
        @numStartIndex int,
        @numEndIndex int,
        @padLength int,
        @totalPadLength int,
        @i int,
        @sameOrderCharsLen int;

    SELECT 
        @totalPadLength = 0,
        @string = RTRIM(LTRIM(@string)),
        @sortString = @string,
        @numStartIndex = PATINDEX('%[0-9]%', @string),
        @numEndIndex = 0,
        @i = 1,
        @sameOrderCharsLen = LEN(@sameOrderChars);

    -- Replace all char that has to have the same order by a space.
    WHILE (@i <= @sameOrderCharsLen)
    BEGIN
        SET @sortString = REPLACE(@sortString, SUBSTRING(@sameOrderChars, @i, 1), ' ');
        SET @i = @i + 1;
    END

    -- Pad numbers with zeros.
    WHILE (@numStartIndex <> 0)
    BEGIN
        SET @numStartIndex = @numStartIndex + @numEndIndex;
        SET @numEndIndex = @numStartIndex;

        WHILE(PATINDEX('[0-9]', SUBSTRING(@string, @numEndIndex, 1)) = 1)
        BEGIN
            SET @numEndIndex = @numEndIndex + 1;
        END

        SET @numEndIndex = @numEndIndex - 1;

        SET @padLength = @numberLength - (@numEndIndex + 1 - @numStartIndex);

        IF @padLength < 0
        BEGIN
            SET @padLength = 0;
        END

        SET @sortString = STUFF(
            @sortString,
            @numStartIndex + @totalPadLength,
            0,
            REPLICATE('0', @padLength)
        );

        SET @totalPadLength = @totalPadLength + @padLength;
        SET @numStartIndex = PATINDEX('%[0-9]%', RIGHT(@string, LEN(@string) - @numEndIndex));
    END

    RETURN @sortString;
END

GO

@MarkSteudel आपको इसे देना होगा और इसे अपने लिए परीक्षण करना होगा। इससे भी बदतर आप हमेशा स्वरूपित मूल्यों को कैश कर सकते हैं। शायद यही मैं बड़ी तालिकाओं के लिए करूंगा क्योंकि आप क्षेत्र को भी अनुक्रमित कर सकते हैं।
प्लेक्स

15

MySQL इस प्रकार की "प्राकृतिक छँटाई" की अनुमति नहीं देता है, इसलिए यह आपके द्वारा सेट किए गए डेटा को विभाजित करने के लिए सबसे अच्छा तरीका है जैसा कि आपने ऊपर वर्णित किया है (अलग आईडी फ़ील्ड, आदि), या असफल। एक गैर-शीर्षक तत्व, आपके db में अनुक्रमित तत्व (दिनांक, db में सम्मिलित आईडी आदि) के आधार पर एक प्रकार का प्रदर्शन करते हैं।

Db होने से आपके लिए छँटाई लगभग हमेशा अपनी प्रोग्रामिंग भाषा में बड़े डेटा सेट पढ़ने और वहाँ छाँटने की तुलना में जल्दी हो जाती है, इसलिए यदि यहाँ db स्कीमा पर आपका कोई नियंत्रण है, तो जोड़कर देखें आसानी से छाँटे गए फ़ील्ड जैसा कि ऊपर वर्णित है, यह आपको लंबे समय में परेशानी और रखरखाव से बचाएगा।

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

SELECT * FROM table ORDER BY CAST(mid(name, 6, LENGTH(c) -5) AS unsigned) 

इस प्रकार का समाधान केवल आपके अंतिम काल्पनिक उदाहरण के ऊपर काम करने के लिए किया जा सकता है, लेकिन विशेष रूप से लचीला नहीं है और साफ तौर पर एक डेटासेट में विस्तार करने की संभावना नहीं है, जैसे "वॉरहैमर 40,000" और "जेम्स बॉन्ड 007" मुझे डर है ।


9

इसलिए, जब मुझे पता है कि आपको एक संतोषजनक उत्तर मिल गया है, तो मैं थोड़ी देर के लिए इस समस्या से जूझ रहा था, और हमने पहले से निर्धारित कर लिया था कि यह SQL में यथोचित नहीं किया जा सकता है और हम JSON पर जावास्क्रिप्ट का उपयोग करने जा रहे हैं सरणी।

यहां बताया गया है कि मैंने इसे सिर्फ SQL का उपयोग करके कैसे हल किया। उम्मीद है कि यह दूसरों के लिए उपयोगी है:

मेरे पास डेटा था जैसे:

दृश्य 1
दृश्य 1 ए
दृश्य 1 बी
दृश्य 2 ए
दृश्य 3
...
दृश्य 101
दृश्य XXA1
दृश्य XXA2

मैं वास्तव में "कास्ट" चीजों को नहीं करता था, हालांकि मुझे लगता है कि यह भी काम कर सकता है।

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

मेरा ORDER BYखंड ऐसा लगता है:

ORDER BY LPAD(REPLACE(`table`.`column`,'Scene ',''),10,'0')

जाहिर है कि यह मूल समस्या के साथ मदद नहीं करता है जो कि एक समान नहीं थी - लेकिन मुझे लगता है कि यह संभवत: कई अन्य संबंधित समस्याओं के लिए काम करेगा, इसलिए इसे वहां से बाहर करना चाहिए।


LPAD()संकेत काफी मददगार था। मेरे पास सॉर्ट करने के लिए शब्द और नंबर हैं, LPADमैं स्वाभाविक रूप से संख्याओं को सॉर्ट कर सकता हूं। और CONCATनॉन-नंबर्स को इग्नोर करते हुए । मेरी क्वेरी इस तरह दिखती है (अन्य नाम सॉर्ट करने के लिए कॉलम है): IF(CONCAT("",alias*1)=alias, LPAD(alias,5,"0"), alias) ASC;No
काई नैक

6
  1. अपनी तालिका में एक क्रमबद्ध कुंजी (रैंक) जोड़ें। ORDER BY rank

  2. "रिलीज़ डेट" कॉलम का उपयोग करें। ORDER BY release_date

  3. एसक्यूएल से डेटा निकालते समय, अपनी वस्तु को छँटाई करें, उदाहरण के लिए, अगर एक सेट में निकालते हैं, तो इसे एक ट्रीसेट बनाएं, और अपने डेटा मॉडल को तुलनात्मक रूप से लागू करें और प्राकृतिक प्रकार के एल्गोरिथ्म को यहां लागू करें (यदि आप उपयोग कर रहे हैं तो प्रविष्टि सॉर्ट पर्याप्त होगा) संग्रह के बिना एक भाषा) जब आप अपना मॉडल बनाते हैं तो आप एक-एक करके SQL से पंक्तियों को पढ़ रहे होंगे और इसे संग्रह में सम्मिलित करेंगे)


5

रिचर्ड टोथ से सर्वश्रेष्ठ प्रतिक्रिया के बारे में https://stackoverflow.com/a/12257917/4052357

UTF8 एन्कोडेड स्ट्रिंग्स के लिए देखें जिसमें 2byte (या अधिक) वर्ण और संख्याएँ हैं

12 南新宿

MySQL का उपयोग LENGTH()में udf_NaturalSortFormatसमारोह स्ट्रिंग के बाइट लंबाई वापस आ जाएगी और गलत हो, बजाय का उपयोग CHAR_LENGTH()जो सही वर्ण लंबाई वापस आ जाएगी।

मेरे मामले में LENGTH()कभी-कभी पूर्ण नहीं होने के कारण प्रश्नों का उपयोग करके और MySQL के लिए 100% CPU उपयोग में परिणाम

DROP FUNCTION IF EXISTS `udf_NaturalSortFormat`;
DELIMITER ;;
CREATE FUNCTION `udf_NaturalSortFormat` (`instring` varchar(4000), `numberLength` int, `sameOrderChars` char(50)) 
RETURNS varchar(4000)
LANGUAGE SQL
DETERMINISTIC
NO SQL
SQL SECURITY INVOKER
BEGIN
    DECLARE sortString varchar(4000);
    DECLARE numStartIndex int;
    DECLARE numEndIndex int;
    DECLARE padLength int;
    DECLARE totalPadLength int;
    DECLARE i int;
    DECLARE sameOrderCharsLen int;

    SET totalPadLength = 0;
    SET instring = TRIM(instring);
    SET sortString = instring;
    SET numStartIndex = udf_FirstNumberPos(instring);
    SET numEndIndex = 0;
    SET i = 1;
    SET sameOrderCharsLen = CHAR_LENGTH(sameOrderChars);

    WHILE (i <= sameOrderCharsLen) DO
        SET sortString = REPLACE(sortString, SUBSTRING(sameOrderChars, i, 1), ' ');
        SET i = i + 1;
    END WHILE;

    WHILE (numStartIndex <> 0) DO
        SET numStartIndex = numStartIndex + numEndIndex;
        SET numEndIndex = numStartIndex;

        WHILE (udf_FirstNumberPos(SUBSTRING(instring, numEndIndex, 1)) = 1) DO
            SET numEndIndex = numEndIndex + 1;
        END WHILE;

        SET numEndIndex = numEndIndex - 1;

        SET padLength = numberLength - (numEndIndex + 1 - numStartIndex);

        IF padLength < 0 THEN
            SET padLength = 0;
        END IF;

        SET sortString = INSERT(sortString, numStartIndex + totalPadLength, 0, REPEAT('0', padLength));

        SET totalPadLength = totalPadLength + padLength;
        SET numStartIndex = udf_FirstNumberPos(RIGHT(instring, CHAR_LENGTH(instring) - numEndIndex));
    END WHILE;

    RETURN sortString;
END
;;

पी एस मैं इसे मूल के लिए एक टिप्पणी के रूप में जोड़ा होगा, लेकिन मेरे पास पर्याप्त प्रतिष्ठा नहीं है (अभी तक)


4

"सॉर्ट की" के लिए एक फ़ील्ड जोड़ें जिसमें अंकों के सभी तार शून्य-गद्देदार होते हैं जो एक निश्चित लंबाई तक होते हैं और फिर इसके बजाय उस फ़ील्ड पर सॉर्ट करते हैं।

यदि आपके पास अंकों के लंबे तार हो सकते हैं, तो एक और विधि अंकों की प्रत्येक स्ट्रिंग के लिए अंकों की संख्या (निश्चित-चौड़ाई, शून्य-गद्देदार) को प्रस्तुत करना है। उदाहरण के लिए, यदि आपके पास एक पंक्ति में 99 से अधिक अंक नहीं होंगे, तो "सुपर ब्लास्ट 10 अल्ट्रा" के लिए सॉर्ट कुंजी "सुपर ब्लास्ट 0210 अल्ट्रा" होगी।


4

: आदेश करने के लिए
0
1
2
10
23
101
205
1000
एक
aac

casdsadsa
सीएसएस

इस क्वेरी का उपयोग करें:

चुनते हैं 
    आम नाम 
से 
    तालिका नाम 
द्वारा आदेश
    column_name REGEXP '^ \ d * [^ \ _- z & \ _ \ _ \ _ \ _ \ _ \ _ \ _ \ _ \ _ \ _ \ _ \ _ \ _ (\) \ _? \: \\, \ _? \ _ \ _ \ _ | \ _ \ _] 'DESC, 
    column_name + 0, 
    आम नाम;

दुर्भाग्य से यह नीचे अगर आप मान ऐसे में के रूप में जोड़ टूट जाता है a1, a2, a11, आदि ...
random_user_name

4

यदि आप पहिया को फिर से स्थापित नहीं करना चाहते हैं या बहुत सारे कोड के साथ सिरदर्द है जो काम नहीं करता है, तो बस Drupal Natural Sort का उपयोग करें ... बस SQL ​​चलाएं जो ज़िपित (MySQL या Postgre) आता है, और यही है। एक प्रश्न बनाते समय, बस आदेश का उपयोग करें:

... ORDER BY natsort_canon(column_name, 'natural')

इसके लिए धन्यवाद, मैं सभी प्रकार के समाधानों की कोशिश कर रहा हूं (हा हा देखिए मैंने वहां क्या किया?) लेकिन उनमें से किसी ने भी वास्तव में सभी डेटा के लिए काम नहीं किया। ड्रुपल फ़ंक्शन ने एक आकर्षण की तरह काम किया। पोस्ट करने का शुक्रिया।
बेन हिचकॉक

यह काम करता है लेकिन अंत में संख्याओं को
क्रमबद्ध

4

एक अन्य विकल्प mysql से डेटा खींचने के बाद मेमोरी में सॉर्टिंग करना है। हालांकि यह प्रदर्शन के दृष्टिकोण से सबसे अच्छा विकल्प नहीं होगा, यदि आप बड़ी सूची को नहीं छांट रहे हैं तो आपको ठीक होना चाहिए।

यदि आप जेफ की पोस्ट पर एक नज़र डालते हैं, तो आप कभी भी जिस भाषा के साथ काम कर रहे हैं उसके लिए बहुत सारे एल्गोरिदम पा सकते हैं। इंसानों के लिए छँटाई: प्राकृतिक क्रमबद्ध क्रम


2

आप एक गतिशील तरीके से "सॉर्ट कॉलम" भी बना सकते हैं:

SELECT name, (name = '-') boolDash, (name = '0') boolZero, (name+0 > 0) boolNum 
FROM table 
ORDER BY boolDash DESC, boolZero DESC, boolNum DESC, (name+0), name

इस तरह, आप सॉर्ट करने के लिए समूह बना सकते हैं।

मेरी क्वेरी में, मैं सब कुछ के सामने '-', फिर नंबर, फिर पाठ चाहता था। जिसके परिणामस्वरूप कुछ हो सकता है:

-
0    
1
2
3
4
5
10
13
19
99
102
Chair
Dog
Table
Windows

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


मुझे नहीं पता कि यह कैसा प्रदर्शन होगा। मैं इसे बिना किसी असुविधा के हर समय उपयोग कर रहा हूं। मेरा डेटाबेस बड़ा नहीं है।
एंटोनी

1

यदि आप PHP का उपयोग कर रहे हैं, तो आप php में प्राकृतिक प्रकार कर सकते हैं।

$keys = array();
$values = array();
foreach ($results as $index => $row) {
   $key = $row['name'].'__'.$index; // Add the index to create an unique key.
   $keys[] = $key;
   $values[$key] = $row; 
}
natsort($keys);
$sortedValues = array(); 
foreach($keys as $index) {
  $sortedValues[] = $values[$index]; 
}

मुझे उम्मीद है कि MySQL भविष्य के संस्करण में प्राकृतिक छँटाई को लागू करेगा, लेकिन 2003 के बाद से सुविधा अनुरोध (# 1588) खुला है, इसलिए मैं अपनी सांस नहीं रोक पा रहा हूँ।


सैद्धांतिक रूप से यह संभव है, लेकिन मुझे पहले अपने वेबसर्वर को सभी डेटाबेस रिकॉर्ड पढ़ने होंगे।
ब्लेम

वैकल्पिक रूप से विचार करें: usort($mydata, function ($item1, $item2) { return strnatcmp($item1['key'], $item2['key']); });(मेरे पास एक साहचर्य सरणी है और कुंजी द्वारा क्रमबद्ध है।) Ref: stackoverflow.com/q/12426825/1066234
Kai Noack

1

@ Plaix / रिचर्ड टोथ / ल्यूक होगेट की सबसे अच्छी प्रतिक्रिया का एक सरलीकृत गैर-यूडीएफ संस्करण, जो केवल क्षेत्र में पहले पूर्णांक के लिए काम करता है,

SELECT name,
LEAST(
    IFNULL(NULLIF(LOCATE('0', name), 0), ~0),
    IFNULL(NULLIF(LOCATE('1', name), 0), ~0),
    IFNULL(NULLIF(LOCATE('2', name), 0), ~0),
    IFNULL(NULLIF(LOCATE('3', name), 0), ~0),
    IFNULL(NULLIF(LOCATE('4', name), 0), ~0),
    IFNULL(NULLIF(LOCATE('5', name), 0), ~0),
    IFNULL(NULLIF(LOCATE('6', name), 0), ~0),
    IFNULL(NULLIF(LOCATE('7', name), 0), ~0),
    IFNULL(NULLIF(LOCATE('8', name), 0), ~0),
    IFNULL(NULLIF(LOCATE('9', name), 0), ~0)
) AS first_int
FROM table
ORDER BY IF(first_int = ~0, name, CONCAT(
    SUBSTR(name, 1, first_int - 1),
    LPAD(CAST(SUBSTR(name, first_int) AS UNSIGNED), LENGTH(~0), '0'),
    SUBSTR(name, first_int + LENGTH(CAST(SUBSTR(name, first_int) AS UNSIGNED)))
)) ASC

1

मैंने कई समाधानों की कोशिश की है लेकिन वास्तव में यह बहुत सरल है:

SELECT test_column FROM test_table ORDER BY LENGTH(test_column) DESC, test_column DESC

/* 
Result 
--------
value_1
value_2
value_3
value_4
value_5
value_6
value_7
value_8
value_9
value_10
value_11
value_12
value_13
value_14
value_15
...
*/

1
प्रारूप में संख्याओं को क्रमबद्ध करने के लिए बहुत अच्छी तरह से काम करता है 23-4244। धन्यवाद :)
Pyton

1
केवल इस परीक्षण डेटा के साथ काम करता है क्योंकि संख्या से पहले के तार सभी समान हैं। z_99वहाँ एक मूल्य में चिपके रहने की कोशिश करें और इसे शीर्ष पर रखा जाएगा, लेकिन zबाद में आता है v
सैमुअल नेफ

@SamuelNeff कृपया SQL: ORDER BY LENGTH (test_column) DESC, test_column DESC को हाँ देखें, क्योंकि यह पहले कॉलम की लंबाई के अनुसार क्रमबद्ध होगा। यह तालिका के एक उपसर्ग समूह को छाँटने में अच्छी तरह से काम करता है जो अन्यथा आप केवल "test_column DESC" के साथ क्रमबद्ध नहीं कर पाएंगे
तारिक

1

बहुत सारे अन्य उत्तर जो मैं यहां (और डुप्लिकेट प्रश्नों में) देख रहा हूं, मूल रूप से केवल बहुत विशेष रूप से स्वरूपित डेटा के लिए काम करते हैं , उदाहरण के लिए एक स्ट्रिंग जो पूरी तरह से एक संख्या है, या जिसके लिए एक निश्चित-लंबाई वाला अल्फाबेटिक उपसर्ग है। यह सामान्य मामले में काम नहीं कर रहा है।

यह सच है कि MySQL में 100% सामान्य नेट-सॉर्ट को लागू करने का वास्तव में कोई तरीका नहीं है, क्योंकि यह करने के लिए कि आप वास्तव में क्या संशोधित है तुलनात्मक फ़ंक्शन की , जो कि जब / जब टकराव होता है, तो स्ट्रिंग्स और संख्यात्मक प्रकार के लेक्सोग्राफ़िक सॉर्टिंग के बीच स्विच होता है एक संख्या। ऐसा कोड किसी भी एल्गोरिथ्म को लागू कर सकता है जिसे आप दो भागों के भीतर संख्यात्मक भागों को पहचानने और तुलना करने की इच्छा कर सकते हैं। दुर्भाग्य से, हालांकि, MySQL में तुलनात्मक फ़ंक्शन इसके कोड के लिए आंतरिक है, और उपयोगकर्ता द्वारा परिवर्तित नहीं किया जा सकता है।

यह किसी प्रकार का एक हैक छोड़ता है, जहाँ आप अपने स्ट्रिंग के लिए एक सॉर्ट कुंजी बनाने का प्रयास करते हैं जिसमें संख्यात्मक भाग फिर से स्वरूपित होते हैं ताकि मानक लेक्सिकोग्राफिक प्रकार वास्तव में उन्हें आपके इच्छित तरीके से सॉर्ट करें

सादे पूर्णांकों के लिए कुछ अधिकतम अंकों तक, स्पष्ट समाधान यह है कि उन्हें केवल शून्य पर रखें ताकि वे निश्चित चौड़ाई वाले हों। यह Drupal plugin और @plalx / @RichardToth के समाधान द्वारा लिया गया दृष्टिकोण है। (@ क्रिश्चियन के पास एक अलग और बहुत अधिक जटिल समाधान है, लेकिन यह कोई लाभ नहीं प्रदान करता है जो मैं देख सकता हूं)।

जैसा कि @tye बताते हैं, आप इस पर प्रत्येक अंक के लिए एक निश्चित-अंक की लंबाई बढ़ाकर सुधार कर सकते हैं, बजाए इसे केवल बाएं-पैड के। वहाँ बहुत है, बहुत अधिक आप पर सुधार कर सकते हैं, हालांकि, यहां तक ​​कि क्या अनिवार्य रूप से एक अजीब हैक है की सीमाओं को देखते हुए। फिर भी, वहाँ कोई पूर्व निर्मित समाधान नहीं लगता है!

उदाहरण के लिए, किस बारे में:

  • प्लस और माइनस संकेत? +10 बनाम 10 बनाम -10
  • दशमलव? 8.2, 8.5, 1.006, .75
  • अग्रणी शून्य? 020, 030, 00000922
  • हजार विभाजक? "1,001 Dalmations" बनाम "1001 Dalmations"
  • संस्करण संख्या? MariaDB v10.3.18 बनाम MariaDB v10.3.3
  • बहुत लंबी संख्या? 103,768,276,592,092,364,859,236,487,687,870,234,598.55

@ Tye की विधि पर विस्तार करते हुए, मैंने एक काफी कॉम्पैक्ट NatSortKey () संग्रहित फ़ंक्शन बनाया है जो एक मनमाना स्ट्रिंग को एक नेट-सॉर्ट कुंजी में बदल देगा, और जो उपरोक्त सभी मामलों को संभालता है, यथोचित रूप से कुशल है, और कुल सॉर्ट को संरक्षित करता है- आदेश (कोई दो अलग-अलग स्ट्रिंग्स में सॉर्ट कीज़ नहीं हैं जो बराबर हैं)। एक दूसरे पैरामीटर का उपयोग प्रत्येक स्ट्रिंग में संसाधित संख्याओं की संख्या को सीमित करने के लिए किया जा सकता है (जैसे पहले 10 नंबर, कहते हैं), जिसका उपयोग किसी निश्चित लंबाई के भीतर आउटपुट फिट करने के लिए किया जा सकता है।

नोट: इस 2 पैरामीटर के दिए गए मान के साथ उत्पन्न सॉर्ट-की स्ट्रिंग को केवल पैरामीटर के लिए समान मान के साथ उत्पन्न अन्य स्ट्रिंग्स के खिलाफ सॉर्ट किया जाना चाहिए , अन्यथा वे सही तरीके से सॉर्ट नहीं कर सकते हैं!

आप इसे सीधे क्रम में उपयोग कर सकते हैं, जैसे

SELECT myString FROM myTable ORDER BY NatSortKey(myString,0);  ### 0 means process all numbers - resulting sort key might be quite long for certain inputs

लेकिन बड़ी तालिकाओं की कुशल छंटाई के लिए, दूसरे कॉलम में सॉर्ट कुंजी को प्री-स्टोर करना बेहतर है (संभवतः उस पर एक इंडेक्स के साथ):

INSERT INTO myTable (myString,myStringNSK) VALUES (@theStringValue,NatSortKey(@theStringValue,10)), ...
...
SELECT myString FROM myTable ORDER BY myStringNSK;

[आदर्श रूप से, आप कुंजी कॉलम को एक संगृहीत संग्रहीत कॉलम के रूप में बनाकर स्वचालित रूप से ऐसा करेंगे, जैसे कुछ:

CREATE TABLE myTable (
...
myString varchar(100),
myStringNSK varchar(150) AS (NatSortKey(myString,10)) STORED,
...
KEY (myStringNSK),
...);

लेकिन अभी तक न तो MySQL और न ही MariaDB गणना किए गए कॉलम में संग्रहीत कार्यों की अनुमति देता है , इसलिए दुर्भाग्य से आप अभी तक ऐसा नहीं कर सकते हैं ।]


मेरा कार्य केवल संख्याओं की छंटाई को प्रभावित करता है । यदि आप अन्य प्रकार के सामान्यीकरण कार्य करना चाहते हैं, जैसे कि सभी विराम चिह्न को हटाना, या प्रत्येक छोर से व्हाट्सएप को ट्रिम करना, या सिंगल-स्पेस के साथ मल्टी-व्हाट्सएप अनुक्रमों को बदलना, आप या तो फ़ंक्शन का विस्तार कर सकते हैं, या यह पहले या बाद NatSortKey()में किया जा सकता है। आपके डेटा पर लागू होता है। (मैं REGEXP_REPLACE()इस उद्देश्य के लिए उपयोग करने की सलाह दूंगा)।

यह कुछ हद तक एंग्लो-केंद्रित भी है कि मैं मान लेता हूं। ' एक दशमलव बिंदु के लिए और ',' हजारों-विभाजक के लिए, लेकिन यह संशोधित करने के लिए पर्याप्त होना चाहिए कि क्या आप रिवर्स चाहते हैं, या यदि आप चाहते हैं कि पैरामीटर के रूप में switchable हो।

यह अन्य तरीकों से और सुधार के लिए उत्तरदायी हो सकता है; उदाहरण के लिए यह वर्तमान में निरपेक्ष मान से ऋणात्मक संख्याओं को क्रमबद्ध करता है, इसलिए -1 -2 से पहले आता है, बजाय इसके कि अन्य तरीके से। पाठ के लिए ASC lexicographic क्रम को बनाए रखते हुए संख्याओं के लिए DESC सॉर्ट क्रम निर्दिष्ट करने का कोई तरीका नहीं है। इन दोनों मुद्दों को थोड़ा और काम के साथ तय किया जा सकता है; अगर मुझे समय मिलता है तो मैं कोड को अपडेट कर दूंगा।

इसके बारे में पता करने के लिए बहुत सारे अन्य विवरण हैं - चेस और कोलाजेशन पर कुछ महत्वपूर्ण निर्भरताओं सहित जो आप उपयोग कर रहे हैं - लेकिन मैंने उन सभी को SQL कोड के भीतर एक टिप्पणी ब्लॉक में डाल दिया है। अपने लिए फ़ंक्शन का उपयोग करने से पहले कृपया इसे ध्यान से पढ़ें!

तो, यहाँ कोड है। यदि आपको कोई बग मिल गया है, या एक सुधार है जिसका मैंने उल्लेख नहीं किया है, तो कृपया मुझे टिप्पणियों में बताएं!


delimiter $$
CREATE DEFINER=CURRENT_USER FUNCTION NatSortKey (s varchar(100), n int) RETURNS varchar(350) DETERMINISTIC
BEGIN
/****
  Converts numbers in the input string s into a format such that sorting results in a nat-sort.
  Numbers of up to 359 digits (before the decimal point, if one is present) are supported.  Sort results are undefined if the input string contains numbers longer than this.
  For n>0, only the first n numbers in the input string will be converted for nat-sort (so strings that differ only after the first n numbers will not nat-sort amongst themselves).
  Total sort-ordering is preserved, i.e. if s1!=s2, then NatSortKey(s1,n)!=NatSortKey(s2,n), for any given n.
  Numbers may contain ',' as a thousands separator, and '.' as a decimal point.  To reverse these (as appropriate for some European locales), the code would require modification.
  Numbers preceded by '+' sort with numbers not preceded with either a '+' or '-' sign.
  Negative numbers (preceded with '-') sort before positive numbers, but are sorted in order of ascending absolute value (so -7 sorts BEFORE -1001).
  Numbers with leading zeros sort after the same number with no (or fewer) leading zeros.
  Decimal-part-only numbers (like .75) are recognised, provided the decimal point is not immediately preceded by either another '.', or by a letter-type character.
  Numbers with thousand separators sort after the same number without them.
  Thousand separators are only recognised in numbers with no leading zeros that don't immediately follow a ',', and when they format the number correctly.
  (When not recognised as a thousand separator, a ',' will instead be treated as separating two distinct numbers).
  Version-number-like sequences consisting of 3 or more numbers separated by '.' are treated as distinct entities, and each component number will be nat-sorted.
  The entire entity will sort after any number beginning with the first component (so e.g. 10.2.1 sorts after both 10 and 10.995, but before 11)
  Note that The first number component in an entity like this is also permitted to contain thousand separators.

  To achieve this, numbers within the input string are prefixed and suffixed according to the following format:
  - The number is prefixed by a 2-digit base-36 number representing its length, excluding leading zeros.  If there is a decimal point, this length only includes the integer part of the number.
  - A 3-character suffix is appended after the number (after the decimals if present).
    - The first character is a space, or a '+' sign if the number was preceded by '+'.  Any preceding '+' sign is also removed from the front of the number.
    - This is followed by a 2-digit base-36 number that encodes the number of leading zeros and whether the number was expressed in comma-separated form (e.g. 1,000,000.25 vs 1000000.25)
    - The value of this 2-digit number is: (number of leading zeros)*2 + (1 if comma-separated, 0 otherwise)
  - For version number sequences, each component number has the prefix in front of it, and the separating dots are removed.
    Then there is a single suffix that consists of a ' ' or '+' character, followed by a pair base-36 digits for each number component in the sequence.

  e.g. here is how some simple sample strings get converted:
  'Foo055' --> 'Foo0255 02'
  'Absolute zero is around -273 centigrade' --> 'Absolute zero is around -03273 00 centigrade'
  'The $1,000,000 prize' --> 'The $071000000 01 prize'
  '+99.74 degrees' --> '0299.74+00 degrees'
  'I have 0 apples' --> 'I have 00 02 apples'
  '.5 is the same value as 0000.5000' --> '00.5 00 is the same value as 00.5000 08'
  'MariaDB v10.3.0018' --> 'MariaDB v02100130218 000004'

  The restriction to numbers of up to 359 digits comes from the fact that the first character of the base-36 prefix MUST be a decimal digit, and so the highest permitted prefix value is '9Z' or 359 decimal.
  The code could be modified to handle longer numbers by increasing the size of (both) the prefix and suffix.
  A higher base could also be used (by replacing CONV() with a custom function), provided that the collation you are using sorts the "digits" of the base in the correct order, starting with 0123456789.
  However, while the maximum number length may be increased this way, note that the technique this function uses is NOT applicable where strings may contain numbers of unlimited length.

  The function definition does not specify the charset or collation to be used for string-type parameters or variables:  The default database charset & collation at the time the function is defined will be used.
  This is to make the function code more portable.  However, there are some important restrictions:

  - Collation is important here only when comparing (or storing) the output value from this function, but it MUST order the characters " +0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" in that order for the natural sort to work.
    This is true for most collations, but not all of them, e.g. in Lithuanian 'Y' comes before 'J' (according to Wikipedia).
    To adapt the function to work with such collations, replace CONV() in the function code with a custom function that emits "digits" above 9 that are characters ordered according to the collation in use.

  - For efficiency, the function code uses LENGTH() rather than CHAR_LENGTH() to measure the length of strings that consist only of digits 0-9, '.', and ',' characters.
    This works for any single-byte charset, as well as any charset that maps standard ASCII characters to single bytes (such as utf8 or utf8mb4).
    If using a charset that maps these characters to multiple bytes (such as, e.g. utf16 or utf32), you MUST replace all instances of LENGTH() in the function definition with CHAR_LENGTH()

  Length of the output:

  Each number converted adds 5 characters (2 prefix + 3 suffix) to the length of the string. n is the maximum count of numbers to convert;
  This parameter is provided as a means to limit the maximum output length (to input length + 5*n).
  If you do not require the total-ordering property, you could edit the code to use suffixes of 1 character (space or plus) only; this would reduce the maximum output length for any given n.
  Since a string of length L has at most ((L+1) DIV 2) individual numbers in it (every 2nd character a digit), for n<=0 the maximum output length is (inputlength + 5*((inputlength+1) DIV 2))
  So for the current input length of 100, the maximum output length is 350.
  If changing the input length, the output length must be modified according to the above formula.  The DECLARE statements for x,y,r, and suf must also be modified, as the code comments indicate.
****/
  DECLARE x,y varchar(100);            # need to be same length as input s
  DECLARE r varchar(350) DEFAULT '';   # return value:  needs to be same length as return type
  DECLARE suf varchar(101);   # suffix for a number or version string. Must be (((inputlength+1) DIV 2)*2 + 1) chars to support version strings (e.g. '1.2.33.5'), though it's usually just 3 chars. (Max version string e.g. 1.2. ... .5 has ((length of input + 1) DIV 2) numeric components)
  DECLARE i,j,k int UNSIGNED;
  IF n<=0 THEN SET n := -1; END IF;   # n<=0 means "process all numbers"
  LOOP
    SET i := REGEXP_INSTR(s,'\\d');   # find position of next digit
    IF i=0 OR n=0 THEN RETURN CONCAT(r,s); END IF;   # no more numbers to process -> we're done
    SET n := n-1, suf := ' ';
    IF i>1 THEN
      IF SUBSTRING(s,i-1,1)='.' AND (i=2 OR SUBSTRING(s,i-2,1) RLIKE '[^.\\p{L}\\p{N}\\p{M}\\x{608}\\x{200C}\\x{200D}\\x{2100}-\\x{214F}\\x{24B6}-\\x{24E9}\\x{1F130}-\\x{1F149}\\x{1F150}-\\x{1F169}\\x{1F170}-\\x{1F189}]') AND (SUBSTRING(s,i) NOT RLIKE '^\\d++\\.\\d') THEN SET i:=i-1; END IF;   # Allow decimal number (but not version string) to begin with a '.', provided preceding char is neither another '.', nor a member of the unicode character classes: "Alphabetic", "Letter", "Block=Letterlike Symbols" "Number", "Mark", "Join_Control"
      IF i>1 AND SUBSTRING(s,i-1,1)='+' THEN SET suf := '+', j := i-1; ELSE SET j := i; END IF;   # move any preceding '+' into the suffix, so equal numbers with and without preceding "+" signs sort together
      SET r := CONCAT(r,SUBSTRING(s,1,j-1)); SET s = SUBSTRING(s,i);   # add everything before the number to r and strip it from the start of s; preceding '+' is dropped (not included in either r or s)
    END IF;
    SET x := REGEXP_SUBSTR(s,IF(SUBSTRING(s,1,1) IN ('0','.') OR (SUBSTRING(r,-1)=',' AND suf=' '),'^\\d*+(?:\\.\\d++)*','^(?:[1-9]\\d{0,2}(?:,\\d{3}(?!\\d))++|\\d++)(?:\\.\\d++)*+'));   # capture the number + following decimals (including multiple consecutive '.<digits>' sequences)
    SET s := SUBSTRING(s,LENGTH(x)+1);   # NOTE: LENGTH() can be safely used instead of CHAR_LENGTH() here & below PROVIDED we're using a charset that represents digits, ',' and '.' characters using single bytes (e.g. latin1, utf8)
    SET i := INSTR(x,'.');
    IF i=0 THEN SET y := ''; ELSE SET y := SUBSTRING(x,i); SET x := SUBSTRING(x,1,i-1); END IF;   # move any following decimals into y
    SET i := LENGTH(x);
    SET x := REPLACE(x,',','');
    SET j := LENGTH(x);
    SET x := TRIM(LEADING '0' FROM x);   # strip leading zeros
    SET k := LENGTH(x);
    SET suf := CONCAT(suf,LPAD(CONV(LEAST((j-k)*2,1294) + IF(i=j,0,1),10,36),2,'0'));   # (j-k)*2 + IF(i=j,0,1) = (count of leading zeros)*2 + (1 if there are thousands-separators, 0 otherwise)  Note the first term is bounded to <= base-36 'ZY' as it must fit within 2 characters
    SET i := LOCATE('.',y,2);
    IF i=0 THEN
      SET r := CONCAT(r,LPAD(CONV(LEAST(k,359),10,36),2,'0'),x,y,suf);   # k = count of digits in number, bounded to be <= '9Z' base-36
    ELSE   # encode a version number (like 3.12.707, etc)
      SET r := CONCAT(r,LPAD(CONV(LEAST(k,359),10,36),2,'0'),x);   # k = count of digits in number, bounded to be <= '9Z' base-36
      WHILE LENGTH(y)>0 AND n!=0 DO
        IF i=0 THEN SET x := SUBSTRING(y,2); SET y := ''; ELSE SET x := SUBSTRING(y,2,i-2); SET y := SUBSTRING(y,i); SET i := LOCATE('.',y,2); END IF;
        SET j := LENGTH(x);
        SET x := TRIM(LEADING '0' FROM x);   # strip leading zeros
        SET k := LENGTH(x);
        SET r := CONCAT(r,LPAD(CONV(LEAST(k,359),10,36),2,'0'),x);   # k = count of digits in number, bounded to be <= '9Z' base-36
        SET suf := CONCAT(suf,LPAD(CONV(LEAST((j-k)*2,1294),10,36),2,'0'));   # (j-k)*2 = (count of leading zeros)*2, bounded to fit within 2 base-36 digits
        SET n := n-1;
      END WHILE;
      SET r := CONCAT(r,y,suf);
    END IF;
  END LOOP;
END
$$
delimiter ;

मैं MySQL में एक शुरुआत कर रहा हूँ और यह कोशिश की। यह त्रुटि मिली: "# 1305 - FUNCTION mydatabase.REGEXP_INSTR मौजूद नहीं है"। कोई उपाय?
जॉन टी

किसी भी अन्य नौसिखिया के लिए वहाँ। मेरे पास MySQL 8.0 स्थापित नहीं था। यह REGEXP_INSTR (और अन्य REGEXP सामान) के लिए आवश्यक है।
जॉन टी

बस एक गंभीर बग को NatSortKey में तय किया गया था: एक गलत रेगेक्स चरित्र था। यदि आपने स्वयं इस फ़ंक्शन का उपयोग किया है, तो कृपया अपना कोड अपडेट करें!
चल रहा


0

यहाँ एक सरल है यदि शीर्षक में केवल एक संख्या के रूप में संस्करण है:

ORDER BY CAST(REGEXP_REPLACE(title, "[a-zA-Z]+", "") AS INT)';

अन्यथा आप सरल एसक्यूएल का उपयोग कर सकते हैं यदि आप एक पैटर्न का उपयोग करते हैं (यह पैटर्न संस्करण से पहले एक # का उपयोग करता है):

create table titles(title);

insert into titles (title) values 
('Final Fantasy'),
('Final Fantasy #03'),
('Final Fantasy #11'),
('Final Fantasy #10'),
('Final Fantasy #2'),
('Bond 007 ##2'),
('Final Fantasy #01'),
('Bond 007'),
('Final Fantasy #11}');

select REGEXP_REPLACE(title, "#([0-9]+)", "\\1") as title from titles
ORDER BY REGEXP_REPLACE(title, "#[0-9]+", ""),
CAST(REGEXP_REPLACE(title, ".*#([0-9]+).*", "\\1") AS INT);     
+-------------------+
| title             |
+-------------------+
| Bond 007          |
| Bond 007 #2       |
| Final Fantasy     |
| Final Fantasy 01  |
| Final Fantasy 2   |
| Final Fantasy 03  |
| Final Fantasy 10  |
| Final Fantasy 11  |
| Final Fantasy 11} |
+-------------------+
8 rows in set, 2 warnings (0.001 sec)

यदि आवश्यक हो तो आप अन्य पैटर्न का उपयोग कर सकते हैं। उदाहरण के लिए यदि आपके पास एक फिल्म "मैं # 1" हूं और "मैं # 1 भाग 2 हूं" तो शायद संस्करण को लपेटें जैसे "अंतिम काल्पनिक" 11 ""


-4

मुझे पता है कि यह विषय प्राचीन है लेकिन मुझे लगता है कि मुझे ऐसा करने का एक तरीका मिल गया है:

SELECT * FROM `table` ORDER BY 
CONCAT(
  GREATEST(
    LOCATE('1', name),
    LOCATE('2', name),
    LOCATE('3', name),
    LOCATE('4', name),
    LOCATE('5', name),
    LOCATE('6', name),
    LOCATE('7', name),
    LOCATE('8', name),
    LOCATE('9', name)
   ),
   name
) ASC

स्क्रैप करें कि, यह निम्नलिखित सेट को गलत तरीके से हल करता है (यह बेकार है):

अंतिम काल्पनिक 1 अंतिम काल्पनिक 2 अंतिम काल्पनिक 5 अंतिम काल्पनिक 7 अंतिम काल्पनिक 7: बच्चों को अंतिम काल्पनिक 12 अंतिम काल्पनिक 112 एफएफ 1 एफएफ 2


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