LIKE N '% searching%' के लिए कोई भी यूनिकोड वर्ण और = N' 'मैच कई क्यों खोजता है?


21
DECLARE @T TABLE(
  Col NCHAR(1));

INSERT INTO @T
VALUES      (N'A'),
            (N'B'),
            (N'C'),
            (N'Ƕ'),
            (N'Ƿ'),
            (N'Ǹ');

SELECT *
FROM   @T
WHERE  Col LIKE N'%�%'

रिटर्न

Col
A
B
C
Ƕ
Ƿ
Ǹ

SELECT *
FROM   @T
WHERE  Col = N'�' 

रिटर्न

Col
Ƕ
Ƿ
Ǹ

नीचे के साथ हर संभव डबल बाइट "वर्ण" उत्पन्न करना दिखाता है कि =संस्करण उनमें से 21,229 और उन LIKE N'%�%'सभी के संस्करण से मेल खाता है (मैंने उसी परिणाम के साथ कुछ गैर बाइनरी टकराव की कोशिश की है)।

WITH T(I, N)
AS 
(
SELECT TOP 65536 ROW_NUMBER() OVER (ORDER BY @@SPID),
                 NCHAR(ROW_NUMBER() OVER (ORDER BY @@SPID))
FROM master..spt_values v1, 
     master..spt_values v2
)
SELECT I, N 
FROM T
WHERE N = N'�'  

कोई भी किसी भी प्रकाश को बहा सकता है जैसे कि यहाँ क्या चल रहा है?

COLLATE Latin1_General_BINतब का उपयोग करना एकल चरित्र से मेल खाता है NCHAR(65533)- लेकिन सवाल यह समझना है कि यह दूसरे मामले में किन नियमों का उपयोग करता है। उन 21,229 पात्रों के बारे में क्या खास है जो मेल खाते हैं =और क्यों सब कुछ वाइल्डकार्ड से मेल खाता है? मुझे लगता है कि इसके पीछे कुछ कारण है जो मुझे याद आ रहा है।

nchar(65534)[और 21k दूसरों] बस के रूप में अच्छी तरह से काम करते हैं nchar(65533)। यह प्रश्न nchar(502) समान रूप से उपयोग करने से प्रतिपादित किया जा सकता था - यह दोनों LIKE N'%Ƕ%'(हर चीज से मेल खाता) और =मामले में समान व्यवहार करता है । यह शायद काफी बड़ा सुराग है।

SELECTअंतिम क्वेरी में परिवर्तन से SELECT I, N, RANK() OVER(ORDER BY N)पता चलता है कि SQL सर्वर वर्णों को रैंक नहीं कर सकता है। ऐसा लगता है कि किसी भी चरित्र को कोलॉलेशन द्वारा संभाला नहीं गया है समकक्ष माना जाता है।

Latin1_General_100_CS_ASटकराव वाला एक डेटाबेस 5840 मैचों का उत्पादन करता है। Latin1_General_100_CS_ASनीचे कटौती =मैचों काफी काफी है, लेकिन परिवर्तन नहीं करता है LIKEव्यवहार। ऐसा लगता है कि पात्रों का एक पॉट है जो बाद के टकरावों में छोटा हो गया है जो सभी की तुलना बराबर करते हैं और LIKEफिर वाइल्डकार्ड खोजों में अनदेखा किया जाता है ।

मैं SQL सर्वर 2016 का उपयोग कर रहा हूं। प्रतीक यूनिकोड प्रतिस्थापन चरित्र है, लेकिन UCS-2 एन्कोडिंग में केवल अमान्य वर्ण 55296 - 57343 AFAIK हैं और यह स्पष्ट रूप से पूरी तरह से मान्य कोड बिंदुओं से मेल खा रहा है जैसे N'Ԛ'कि इस श्रेणी में नहीं हैं।

इन सभी पात्रों के लिए खाली स्ट्रिंग की तरह व्यवहार करते हैं LIKEऔर =। वे समतुल्य के रूप में भी मूल्यांकन करते हैं। N'' = N'�'सच है, और आप इसे बिना किसी प्रभाव LIKEके एकल रिक्त स्थान की तुलना में छोड़ सकते हैं LIKE '_' + nchar(65533) + '_'LENतुलनाएं अलग परिणाम देती हैं, लेकिन यह शायद केवल कुछ स्ट्रिंग फ़ंक्शन हैं।

मुझे लगता है कि LIKEइस मामले के लिए व्यवहार सही है; यह एक अज्ञात मूल्य (जो कुछ भी हो सकता है) की तरह व्यवहार करता है। यह इन अन्य पात्रों के लिए भी होता है:

  • nchar(11217) (अनिश्चितता संकेत)
  • nchar(65532) (ऑब्जेक्ट रिप्लेसमेंट कैरेक्टर)
  • nchar(65533) (प्रतिस्थापन चरित्र)
  • nchar(65534) (चरित्र नहीं)

इसलिए यदि मैं सभी चिह्नों को ढूंढना चाहता हूं जो समान संकेत के साथ अनिश्चितता का प्रतिनिधित्व करते हैं तो मैं एक ऐसा कोलाज का उपयोग करूंगा जो पूरक वर्णों का समर्थन करता है Latin1_General_100_CI_AS_SC

मुझे लगता है कि ये "गैर-भारित पात्रों" का समूह हैं, जो प्रलेखन, Collation और Unicode समर्थन में वर्णित हैं ।

जवाबों:


9

कैसे एक "चरित्र" (जिसमें कई कोड पॉइंट शामिल हो सकते हैं: एक दूसरे से तुलना करने वाले जोड़े, पात्रों का संयोजन, सरोगेट करें) नियमों के बजाय जटिल सेट पर आधारित है। यूनिकोड विनिर्देशन में दर्शाई गई सभी भाषाओं में पाए जाने वाले सभी विभिन्न (और कभी-कभी "निराला") नियमों की आवश्यकता के कारण यह बहुत जटिल है । यह प्रणाली सभी NVARCHARडेटा के लिए गैर-बाइनरी Collations पर लागू होती है , और VARCHARडेटा के लिए जो Windows Collation का उपयोग कर रहा है और SQL सर्वर Collation (एक के साथ शुरू होने वाला SQL_) नहीं। यह सिस्टम VARCHARSQL सर्वर Collation का उपयोग करने वाले डेटा पर लागू नहीं होता है क्योंकि वे साधारण मैपिंग का उपयोग करते हैं।

अधिकांश नियमों को यूनिकोड कॉलेशन एल्गोरिथ्म (UCA) में परिभाषित किया गया है । उन नियमों में से कुछ, और कुछ यूसीए में शामिल नहीं हैं:

  1. allkeys.txtफ़ाइल में दिया गया डिफ़ॉल्ट ऑर्डर / वजन (नीचे दिया गया)
  2. कौन सी संवेदनशीलता और विकल्पों का उपयोग किया जा रहा है (जैसे कि यह संवेदनशील या असंवेदनशील है ?, और यदि संवेदनशील है, तो क्या यह ऊपरी-मामला पहले या निचले मामले में है?)
  3. कोई भी स्थानीय-आधारित ओवरराइड।
  4. यूनिकोड मानक के संस्करण का उपयोग किया जा रहा है।
  5. "मानव" कारक (यानी यूनिकोड एक विनिर्देश है, सॉफ्टवेयर नहीं है, और इस प्रकार इसे लागू करने के लिए प्रत्येक विक्रेता पर छोड़ दिया जाता है)

मैंने मानव कारक के बारे में अंतिम बिंदु पर जोर देकर स्पष्ट रूप से यह स्पष्ट करने के लिए कहा कि किसी को SQL सर्वर से हमेशा विनिर्देश के अनुसार 100% व्यवहार करने की उम्मीद नहीं करनी चाहिए।

यहां ओवरराइडिंग कारक प्रत्येक कोड पॉइंट को दिया गया वेटिंग है, और यह तथ्य कि मल्टीपल कोड पॉइंट्स एक ही वेट स्पेसिफिकेशन साझा कर सकते हैं। आप यहां बुनियादी भार (कोई स्थानीय-विशिष्ट ओवरराइड नहीं) पा सकते हैं (मेरा मानना ​​है कि 100Collations की श्रृंखला यूनिकोड v 5.0 है - Microsoft कनेक्ट आइटम पर टिप्पणियों में अनौपचारिक पुष्टि ):

http://www.unicode.org/Public/UCA/5.0.0/allkeys.txt

प्रश्न में कोड बिंदु - U + FFFD - के रूप में परिभाषित किया गया है:

FFFD  ; [*0F12.0020.0002.FFFD] # REPLACEMENT CHARACTER

यह संकेतन UCA के खंड 9.1 Allkeys फ़ाइल प्रारूप में परिभाषित किया गया है :

<entry>       := <charList> ';' <collElement>+ <eol>
<charList>    := <char>+
<collElement> := "[" <alt> <weight> "." <weight> "." <weight> ("." <weight>)? "]"
<alt>         := "*" | "."

Collation elements marked with a "*" are variable.

यह अंतिम पंक्ति महत्वपूर्ण है क्योंकि हम जिस कोड बिंदु को देख रहे हैं उसमें एक विनिर्देश है जो वास्तव में "*" से शुरू होता है। खंड 3.6 परिवर्तनीय भार में Collation कॉन्फ़िगरेशन मूल्यों के आधार पर चार संभावित व्यवहार परिभाषित हैं, जिनकी हमारे पास कोई सीधी पहुंच नहीं है (ये प्रत्येक Collation के Microsoft कार्यान्वयन में हार्ड-कोडित हैं, जैसे कि केस-संवेदी पहले लो-केस का उपयोग करता है या ऊपरी-मामला पहले, एक संपत्ति जो Collations और अन्य सभी विविधताओं VARCHARका उपयोग कर डेटा के बीच अलग है SQL_)।

मेरे पास यह पूर्ण शोध करने का समय नहीं है कि कौन से रास्ते लिए गए हैं और यह पता लगाने के लिए कि कौन से विकल्प का उपयोग किया जा रहा है ताकि अधिक ठोस प्रमाण दिया जा सके, लेकिन यह कहना सुरक्षित है कि प्रत्येक कोड पॉइंट विनिर्देश में, कुछ है या नहीं माना जाता है कि "बराबर" हमेशा पूर्ण विनिर्देशन का उपयोग करने वाला नहीं है। इस मामले में, हमारे पास "0F12.0020.0002.FFFD" है और सबसे अधिक संभावना है कि यह केवल स्तर 2 और 3 है जिसका उपयोग किया जा रहा है (यानी ।0020.0002। )। ".0020.0002" के लिए नोटपैड ++ में "काउंट" करें। 12,581 मैच (पूरक चरित्रों के साथ, जिन्हें हम अभी तक नहीं निभा रहे हैं) खोजता है। "[*" पर "काउंट" करने से 4049 मैच लौटते हैं। एक RegEx करना "ढूंढें" / "गणना करें" के पैटर्न का उपयोग करना\[\*\d{4}\.0020\.0002832 मैच जीते। तो इस संयोजन में कहीं और, संभवतः कुछ अन्य नियम जो मैं नहीं देख रहा हूं, साथ ही कुछ Microsoft-विशिष्ट कार्यान्वयन विवरण, इस व्यवहार का पूर्ण विवरण है। और स्पष्ट होने के लिए, सभी मिलान वाले पात्रों के लिए व्यवहार समान है क्योंकि वे सभी एक दूसरे से मेल खाते हैं क्योंकि नियमों को लागू करने के बाद वे सभी का वजन समान होता है (मतलब, यह प्रश्न उनमें से किसी एक के बारे में पूछा जा सकता है, नहीं जरूरी श्री )।

आप नीचे दिए गए क्वेरी के साथ देख सकते हैं और COLLATEक्लॉज को परिणामों के अनुसार क्लॉज में बदल सकते हैं कि कैसे विभिन्न संवेदनाएं Collations के दो संस्करणों में काम करती हैं:

;WITH cte AS
(
  SELECT     TOP (65536) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) - 1 AS [Num]
  FROM       [master].sys.columns col
  CROSS JOIN [master].sys.objects obj
)
SELECT cte.Num AS [Decimal],
       CONVERT(VARBINARY(2), cte.Num) AS [Hex],
       NCHAR(cte.Num) AS [Character]
FROM   cte
WHERE  NCHAR(cte.Num) = NCHAR(0xFFFD) COLLATE Latin1_General_100_CS_AS_WS --N'�'
ORDER BY cte.Num;

विभिन्न कोलाज में मिलान वाले पात्रों की विभिन्न गणना नीचे है।

Latin1_General_100_CS_AS_WS   =   5840
Latin1_General_100_CS_AS      =   5841 (The "extra" character is U+3000)
Latin1_General_100_CI_AS      =   5841
Latin1_General_100_CI_AI      =   6311

Latin1_General_CS_AS_WS       = 21,229
Latin1_General_CS_AS          = 21,230
Latin1_General_CI_AS          = 21,230
Latin1_General_CI_AI          = 21,537

ऊपर सूचीबद्ध सभी संप्रत्ययों में N'' = N'�'भी सत्य का मूल्यांकन होता है।

अपडेट करें

मैं थोड़ा और शोध करने में सक्षम था और यहाँ मैंने पाया:

यह "शायद" कैसे काम करना चाहिए

ICU Collation Demo का उपयोग करते हुए , मैंने "en-US-u-va-posix" को लोकेल सेट किया, "प्राइमरी", चेक शो "सॉर्ट कीज़" की स्ट्रेंथ सेट की, और निम्न 4 वर्णों में पेस्ट किया, जिन्हें मैंने कॉपी किया था उपरोक्त क्वेरी के परिणाम ( Latin1_General_100_CI_AIकॉलेशन का उपयोग करते हुए ):

�
Ԩ
ԩ
Ԫ

और वह रिटर्न:

Ԫ
    60 2E 02 .
Ԩ
    60 7A .
ԩ
    60 7A .
�
    FF FD .

फिर, http://unicode.org/cldr/utility/character.jsp?a=fffd पर " " के लिए वर्ण गुणों की जाँच करें और देखें कि स्तर 1 सॉर्ट कुंजी (यानी FF FD) "uca" संपत्ति से मेल खाती है। उस "uca" पर क्लिक करने पर संपत्ति आपको एक खोज पृष्ठ पर ले जाती है - http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3Auca%3DFFFD%3A%DD - जो सिर्फ 1 मैच दिखा रहा है। और, allkeys.txt फ़ाइल में, स्तर 1 प्रकार का वजन दिखाया गया है 0F12, और उसके लिए केवल 1 मैच है।

यह सुनिश्चित करने के लिए कि हम व्यवहार को सही ढंग से व्याख्या कर रहे हैं, मैंने एक और चरित्र को देखा: GREEK CAPETET LETTER OMICRON with VARIA at http://unicode.org/cldr/utility/character.jsp?a=1808 जिस पर "uca" (है) यानी के स्तर 1 प्रकार वजन / संपार्श्विक तत्व) 5F30। उस "5F30" पर क्लिक करने से हमें एक खोज पृष्ठ पर ले जाता है - http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3Auca%3D5F30%3A%DD - 30 मैच दिखा रहा है, 20 बार उन्हें 0 - 65535 रेंज (यानी U + 0000 - U + FFFF) में रखा गया है। Codekey 1FF8 के लिए allkeys.txt फ़ाइल में देखते हुए , हम एक स्तर 1 का वजन देखते हैं 12E0। नोटपैड ++ में एक "काउंट" कर रहा है12E0. 30 मैच दिखाता है (यह यूनिकोड से परिणाम से मेल खाता है। हालांकि यह गारंटी नहीं है क्योंकि फ़ाइल यूनिकोड v 5.0 के लिए है और साइट यूनिकोड v 9.0 डेटा का उपयोग कर रही है)।

SQL सर्वर में, निम्न क्वेरी 20 मैच लौटाती है, जैसे कि यूनिकोड.ऑर्ग खोज 10 पूरक वर्ण हटाते समय:

;WITH cte AS
(
  SELECT TOP (65535) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [Num]
  FROM   [master].sys.columns col
  CROSS JOIN [master].sys.objects obj
)
SELECT cte.Num AS [Decimal],
       CONVERT(VARCHAR(50), CONVERT(VARBINARY(2), cte.Num), 2) AS [Hex],
       NCHAR(cte.Num) AS [Character]
FROM cte
WHERE NCHAR(cte.Num) = NCHAR(0x1FF8) COLLATE Latin1_General_100_CI_AI
ORDER BY cte.Num;

और, बस सुनिश्चित करें, ICU Collation डेमो पेज पर वापस जा रहा है, और SQL सर्वर से 20 परिणामों की सूची से लिए गए निम्नलिखित 3 वर्णों के साथ "इनपुट" बॉक्स में वर्णों की जगह ले रहा है:


𝜪

दिखाता है कि वे, वास्तव में, सभी का समान 5F 30स्तर 1 प्रकार का वजन है (चरित्र संपत्ति पृष्ठ पर "ओका" फ़ील्ड से मेल खाता है)।

एसओ, यह निश्चित रूप से ऐसा लगता है जैसे कि यह विशेष चरित्र कुछ और से मेल नहीं खाना चाहिए ।

यह वास्तव में कैसे काम करता है (कम से कम Microsoft-भूमि में)

SQL सर्वर के विपरीत, .NET के पास एक स्ट्रिंग के लिए SortInfo.GetSortKey विधि के माध्यम से सॉर्ट कुंजी दिखाने का एक साधन है । इस पद्धति का उपयोग करके और केवल U + FFFD वर्ण में पास होने के बाद, यह एक प्रकार की कुंजी देता है 0x0101010100। फिर, 0 - 65535 की सीमा में सभी पात्रों पर पुनरावृत्ति करते हुए यह देखने के लिए कि उनमें से 0x0101010100किसके पास 4529 मैचों की वापसी की कुंजी है । यह SQL सर्वर में लौटे 5840 से बिलकुल भी मेल नहीं खाता (जब Latin1_General_100_CS_AS_WSCollation का उपयोग करते हुए ), लेकिन यह निकटतम है जिसे हम (अभी के लिए) प्राप्त कर सकते हैं, यह देखते हुए कि मैं विंडोज 10 और .NET फ्रेमवर्क संस्करण 4.6.1 चला रहा हूं, जिसमें यूनिकोड v का उपयोग किया गया है चार्ट के अनुसार चार्ट के अनुसार 6.3.0 चार्यूनिकोडइन्फो क्लास के लिए("नोट टू कॉलर्स", "रिमार्क्स" अनुभाग में)। फिलहाल मैं SQLCLR फ़ंक्शन का उपयोग कर रहा हूं और इसलिए लक्ष्य फ्रेमवर्क संस्करण को बदल नहीं सकता। जब मुझे मौका मिलता है तो मैं एक कंसोल ऐप बनाऊंगा और 4.5 के टारगेट फ्रेमवर्क संस्करण का उपयोग करूंगा क्योंकि यह यूनिकोड वी 5.0 का उपयोग करता है, जिसे 100 सीरीज़ कोलाज़ से मेल खाना चाहिए।

कि क्या इस परीक्षण से पता चलता है है, यहां तक कि नेट और U + FFFD के लिए एसक्यूएल सर्वर के बीच मैचों की सटीक एक ही नंबर के बिना, यह बहुत स्पष्ट है कि इस है नहीं एसक्यूएल सर्वर-विशिष्ट व्यवहार, और जानबूझकर या कार्यान्वयन के साथ निरीक्षण किया है कि क्या Microsoft द्वारा, U + FFFD चरित्र वास्तव में काफी कुछ वर्णों से मेल खाता है, भले ही यह यूनिकोड विनिर्देश के अनुसार न हो। और, यह देखते हुए कि यह चरित्र U + 0000 (अशक्त) से मेल खाता है, यह शायद केवल गायब वज़न का मुद्दा है।

भी

=क्वेरी बनाम व्यवहार में अंतर के बारे में LIKE N'%�%', इसे वाइल्डकार्ड और इन (यानी � Ƕ Ƿ Ǹ) वर्णों के लिए अनुपलब्ध (मुझे लगता है) भार के साथ करना है । यदि LIKEस्थिति को बस में बदला जा रहा है LIKE N'�'तो यह =स्थिति के समान 3 पंक्तियों को लौटाता है । यदि वाइल्डकार्ड के साथ समस्या "गायब" वज़न के कारण नहीं है ( btw 0x00द्वारा किसी प्रकार की कुंजी नहीं दी गई है CompareInfo.GetSortKey), तो यह इन वर्णों के कारण हो सकता है संभवतः एक संपत्ति है जो संदर्भ के आधार पर सॉर्ट कुंजी को अलग-अलग करने की अनुमति देती है (अर्थात आसपास के वर्ण) )।


धन्यवाद - allkeys.txt में जुड़ा हुआ है, ऐसा लगता है जैसे कि और कुछ नहीं दिया गया है जैसे कि वजन FFFD( *0F12.0020.0002.FFFDकेवल एक परिणाम की खोज)। @ फॉरेस्ट के अवलोकन से कि वे सभी रिक्त स्ट्रिंग से मेल खाते हैं और इस विषय पर थोड़ा और अधिक पढ़ने से ऐसा लगता है कि विभिन्न गैर बाइनरी कॉलेक्शन में उनके द्वारा साझा किए गए वजन वास्तव में शून्य है जो मुझे विश्वास है।
मार्टिन स्मिथ

1
@MartinSmith ने ICU Collation Demo का उपयोग करके कुछ शोध किए � A a \u24D0और कुछ अन्य जो 5839 मैचों के सेट में थे। ऐसा लग रहा है कि आप पहले वजन को छोड़ नहीं सकते हैं, और यह प्रतिस्थापन चार एकमात्र शुरुआत है 0F12। कई अन्य लोगों का पहला अनोखा वजन भी था, और कई तो पूरी तरह से एलाइक फाइल से गायब थे। तो यह मानवीय त्रुटि के कारण कार्यान्वयन बग हो सकता है। मैंने इस चार्ट को उनके Collations चार्ट में यूनिकोड साइट पर "असमर्थित" समूह में देखा था। कल और देखेंगे।
सोलोमन रटज़की

Rextester 4.5 का उपयोग करता है। मैं वास्तव में उस संस्करण (3385) पर कम मैच देखता हूं। शायद मैं आपके लिए कुछ विकल्प अलग सेट कर रहा हूं? rextester.com/JBWIN31407
मार्टिन स्मिथ

BTW की इस प्रकार की कुंजी 01 01 01 01 00यहां बताया गया है archives.miloush.net/michkap/archive/2007/09/10/4847780.html (जैसी लगती है CompareInfo.InternalGetSortKeyकॉल LCMapStringEx)
मार्टिन स्मिथ

@MartinSmith मैं इसके साथ थोड़ा खेला, लेकिन अभी तक निश्चित नहीं है कि क्या अंतर है। .NET जो OS पर चल रहा है वह कारक में है। यदि मेरे पास समय है तो मैं कल और देखूंगा। मैचों की संख्या के बावजूद, हालांकि, यह कम से कम व्यवहार के कारण की पुष्टि करने के लिए प्रतीत होता है, विशेष रूप से अब जब हम आपके द्वारा जुड़े ब्लॉग और इससे जुड़े कुछ अन्य लोगों के लिए धन्यवाद कुंजी संरचना में कुछ अंतर्दृष्टि रखते हैं। : CharUnicodeInfo पेज मैं से जुड़ा हुआ उल्लेख अंतर्निहित मिलान कॉल है, जो मेरे सुझाव यहां का आधार है connect.microsoft.com/SQLServer/feedback/details/2932336 :-)
सोलोमन Rutzky
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.