2012-04-27 13 views
11

मुझे एक चयन प्रश्न करने की आवश्यकता है जो केस और उच्चारण के लिए असंवेदनशील है। तबआईओएस SQLite में उच्चारण वर्णों से कैसे निपटें?

create table table 
(
    column text collate nocase 
); 

insert into table values ('A'); 
insert into table values ('a'); 
insert into table values ('Á'); 
insert into table values ('á'); 

create index table_cloumn_Index 
    on table (column collate nocase); 

, जब निम्न प्रश्नों को क्रियान्वित मैं उन परिणाम प्राप्त: डेमो उद्देश्यों के लिए, मुझे लगता है कि जैसे एक तालिका बनाने

SELECT * FROM table WHERE column LIKE 'a'; 
> A 
> a 

SELECT * FROM table WHERE column LIKE 'á'; 
> á 

SELECT * FROM table WHERE column LIKE 'Á'; 
> Á 

मुझे लगता है कि निम्नलिखित तो किसी के लिए परिणाम कैसे तय कर सकते हैं प्रश्न इस प्रकार हैं:

> A 
> a 
> Á 
> á 

एसक्लाइट आईओएस पर चल रहा है।

अग्रिम धन्यवाद,

उत्तर

18

दो बुनियादी दृष्टिकोण:

  1. आप तालिका जो अंतर्राष्ट्रीय वर्ण के बिना स्ट्रिंग में एक दूसरे स्तंभ बना सकते हैं। इसके अलावा, इस माध्यमिक खोज कॉलम के खिलाफ खोज करने से पहले, आपको स्ट्रिंग से अंतर्राष्ट्रीय पात्रों को भी खोजना चाहिए, इस तरह से (इस तरह आप गैर-अंतरराष्ट्रीय से गैर-अंतरराष्ट्रीय की तुलना कर रहे हैं)।

    NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 
    string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
    

    तुम भी साथ उच्चारण वर्ण की जगह सकता है:: यदि आप अपने परिणामों को सॉर्ट करने की जरूरत है,

    NSMutableString *mutableString = [string mutableCopy]; 
    CFStringTransform((__bridge CFMutableStringRef)mutableString, NULL, kCFStringTransformStripCombiningMarks, NO); 
    

    वैसे

    यह दिनचर्या मैं अंतर्राष्ट्रीय वर्ण परिवर्तित करने के लिए उपयोग करें , आप मुख्य क्षेत्र के बजाय इस माध्यमिक खोज फ़ील्ड को भी सॉर्ट कर सकते हैं, जो अंतरराष्ट्रीय वर्णों को सॉर्ट करने के लिए SQLite की अक्षमता से उत्पन्न समस्याओं से बच जाएगा।

  2. आप वैकल्पिक रूप से अपने खुद के "कमज़ोर" सी समारोह बना सकते हैं (अपनी कक्षा के लिए @implementation बाहर इस सी समारोह को परिभाषित):

    void unaccented(sqlite3_context *context, int argc, sqlite3_value **argv) 
    { 
        if (argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_TEXT) { 
         sqlite3_result_null(context); 
         return; 
        } 
    
        @autoreleasepool { 
         NSMutableString *string = [NSMutableString stringWithUTF8String:(const char *)sqlite3_value_text(argv[0])]; 
         CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformStripCombiningMarks, NO); 
         sqlite3_result_text(context, [string UTF8String], -1, SQLITE_TRANSIENT); 
        } 
    } 
    

    फिर आप एक SQLite समारोह है कि इस सी-समारोह कॉल करेंगे परिभाषित कर सकते हैं

    - (void)createUnaccentedFunction 
    { 
        if (sqlite3_create_function_v2(database, "unaccented", 1, SQLITE_ANY, NULL, &unaccented, NULL, NULL, NULL) != SQLITE_OK) 
         NSLog(@"%s: sqlite3_create_function_v2 error: %s", __FUNCTION__, sqlite3_errmsg(database)); 
    } 
    

    किया करने के बाद जैसे, आप अब एसक्यूएल में इस नए unaccented समारोह का उपयोग कर सकते: (इस प्रक्रिया में डेटाबेस है, जो प्रभावी जब तक आप उस डेटाबेस को बंद हो जाएगा खोलने के बाद कहते हैं)

    if (sqlite3_prepare_v2(database, "select a from table where unaccented(column) like 'a'", -1, &statement, NULL) != SQLITE_OK) 
        NSLog(@"%s: insert 1: %s", __FUNCTION__, sqlite3_errmsg(database)); 
    
+0

हाँ, मैं भी इस दृष्टिकोण का उपयोग कर रहा था, लेकिन अब मुझे ऐसे डेटाबेस से निपटने की ज़रूरत है जिसे मैं अपनी संरचना नहीं बदल सकता। लेकिन यदि आप कर सकते हैं, और आपका डीबी बहुत बड़ा नहीं है, तो यह जाने का एक आसान तरीका है। –

+0

@LeandroAlves मुझे पता है कि आप इस मुद्दे से पहले चले गए हैं, लेकिन मैं (ए) असंतोष तारों के लिए एक और भिन्नता शामिल करता हूं; और (बी) आपको दिखाता है कि फ्लाई पर SQLite में असंतोष तार कैसे करें। – Rob

+0

@Rob विकल्प 2 निष्पादन के लिए कोड और डेटा को सही तरीके से संभालता है, लेकिन सीपीयू को 99% और मेमोरी> 1000 एमबी लेता है। ऑपरेशन पूर्ण होने के तुरंत बाद 'EXC_BAD_ACCESS (कोड = 2, पता = 0x0)' के साथ एप्लिकेशन क्रैश हो जाता है। क्या इस कोड के साथ मेमोरी उपयोग को नियंत्रित करने के लिए कुछ भी किया जा सकता है? –

4

आप को या तो create some user function, या ओवरराइड की आवश्यकता होगी (अर्थात प्रतिस्थापित करें) like() functions का डिफ़ॉल्ट कार्यान्वयन। डिफ़ॉल्ट रूप से ASCII वर्ण के लिए

SQLite केवल समझता है ऊपरी/निचले मामला: कारण यह है कि SQLite में LIKE ऑपरेटर गैर- ASCII केस-असंवेदनशीलता का समर्थन नहीं करता है। LIKE ऑपरेटर ASCII वर्णों के लिए डिफ़ॉल्ट रूप से केस संवेदनशील है जो ASCII रेंज से बाहर हैं। उदाहरण के लिए, अभिव्यक्ति 'ए' पसंद 'ए' सत्य है लेकिन 'æ' पसंद है 'Æ' गलत है।

यह समझ में आता है अन्यथा स्क्लाइट को विभिन्न संस्कृतियों का समर्थन करने की आवश्यकता होगी क्योंकि मामला एक से दूसरे में भिन्न होता है। एक उदाहरण the capital i in Turkey which is not I but a dotted İ, and the lower-case of I is a dot-less ı है। एसक्लाइट में इस सभी संस्कृति की जानकारी को एम्बेड करना बहुत बोझिल होगा (यानी यह स्क्लाइट ऑब्जेक्ट कोड बढ़ाएगा)।

+0

क्या आपने पहले ही आईओएस पर कोई उपयोगकर्ता फ़ंक्शन बनाया है? क्या आपके पास इसके बारे में कोई नमूना कोड है? ऐसा करने का यह एक कठिन तरीका प्रतीत होता है। –

1

क्वेरी

SELECT * FROM table WHERE column LIKE 'a' 

मेरी तरह समस्या

static void myLow(sqlite3_context *context, int argc, sqlite3_value **argv) 
{ 
    NSString* str = [[NSString alloc] initWithUTF8String: 
          (const char *)sqlite3_value_text(argv[0])]; 
    const char* s = [[str lowercaseString] UTF8String]; 
    sqlite3_result_text(context, s, strlen(s), NULL); 
    [str release]; 
} 

// call it once after opening db 
sqlite3_create_function(_db, "myLow", 1, SQLITE_UTF8,NULL, &myLow, NULL, NULL); 

के समाधान और फिर बजाय है आप का उपयोग करना चाहिए

SELECT * FROM table WHERE myLow(column) LIKE 'a' 
संबंधित मुद्दे