क्यों varchar datatype यूनिकोड मानों की अनुमति देता है?


17

मेरे पास एक वर्चर कॉलम वाली एक टेबल है। यह ट्रेडमार्क (™), कॉपीराइट (©) और अन्य यूनिकोड वर्णों को नीचे दिखाए अनुसार अनुमति दे रहा है।

Create table VarcharUnicodeCheck
(
col1 varchar(100)
)

insert into VarcharUnicodeCheck (col1) values ('MyCompany')
insert into VarcharUnicodeCheck (col1) values ('MyCompany™')
insert into VarcharUnicodeCheck (col1) values ('MyCompany░')
insert into VarcharUnicodeCheck (col1) values ('MyCompanyï')
insert into VarcharUnicodeCheck (col1) values ('MyCompany')

select * from VarcharUnicodeCheck

लेकिन varchar की परिभाषा कहती है, यह गैर-यूनिकोड स्ट्रिंग डेटा की अनुमति देता है। लेकिन ट्रेडमार्क (™) और पंजीकृत (®) प्रतीक यूनिकोड वर्ण हैं। क्या परिभाषा varchar datatype की संपत्ति का विरोध करती है? मैंने पहले एक और दूसरे जैसे लिंक के दोहे पढ़े । लेकिन फिर भी मैं समझ नहीं पाया कि यह यूनिकोड स्ट्रिंग की अनुमति क्यों देता है जब परिभाषा कहती है कि यह केवल गैर-यूनिकोड स्ट्रिंग मूल्यों की अनुमति देता है।


12
सभी वर्ण यूनिकोड वर्ण हैं।
मार्टिन स्मिथ

जब वे UTF-16 / UCS-2 का उपयोग करते हैं, तो Microsoft अक्सर UNICODE का उपयोग करता है। इसलिए वे यूटीएफ -8 भी नहीं गिन सकते क्योंकि UNICODE कुछ संदर्भ है।
कोडइन्चोस

1
@CodesInChaos: मैंने आपकी टिप्पणी को पार्स करने के लिए संघर्ष किया, लेकिन मुझे चिंता है कि आप यूनिकोड को विभिन्न यूटीएफ-एन एन्कोडिंग के साथ भ्रमित कर रहे हैं।
मोनिका

1
@ मर्टिन स्मिथ: यदि सभी वर्ण यूनिकोड वर्ण हैं, तो Microsoft varchar परिभाषा क्यों कहती है कि यह गैर-यूनिकोड स्ट्रिंग डेटा की अनुमति देता है?
शिव

2
विचर में पात्रों के लिए एन्कोडिंग यूनिकोड नहीं है, लेकिन सभी वर्ण यूनिकोड में मौजूद हैं
मार्टिन स्मिथ

जवाबों:


15

लेकिन ट्रेडमार्क (™) और पंजीकृत (®) प्रतीक यूनिकोड वर्ण हैं।

आप यहाँ गलत हैं आपके तार में केवल asciiवर्ण होते हैं ।

यहाँ एक सरल परीक्षण है जो आपको दिखाता है कि आपके पात्र सभी एस्की हैं (+ extended ascii128 और 255 के बीच एससीआई कोड वाले कुछ ):

declare @VarcharUnicodeCheck table
(
col1 varchar(100)
)

insert into @VarcharUnicodeCheck (col1) values ('MyCompany')
insert into @VarcharUnicodeCheck (col1) values ('MyCompany™')
insert into @VarcharUnicodeCheck (col1) values ('MyCompany░')
insert into @VarcharUnicodeCheck (col1) values ('MyCompanyï')
insert into @VarcharUnicodeCheck (col1) values ('MyCompany')

select *,
        right(col1, 1)as last_char, 
        ascii(right(col1, 1)) as_last_char_ascii
from @VarcharUnicodeCheck;

यहाँ आप स्पष्ट रूप से देख सकते हैं कि आपके सभी अक्षर 1-बाइट एन्कोडेड हैं:

यहां छवि विवरण दर्ज करें

हाँ, वे शुद्ध अस्सी वर्ण नहीं हैं, लेकिन वे ASCII हैं

यहां मैं आपको वास्तविक यूनिकोड चरित्र Trademark(™)और उसके कोड और बाइनरी प्रतिनिधित्व दिखाता हूं :

declare @t table (uni_ch nchar(1), ascii_ch char(1));
insert into @t values (N'™', '™');

select unicode(uni_ch) as [unicode of ™], 
       ascii(ascii_ch) [ascii of ™], 
       cast(uni_ch as varbinary(10)) as [uni_ch as varbinary], 
       cast(ascii_ch as varbinary(10)) as [ascii_ch as varbinary]
from @t;

यहां छवि विवरण दर्ज करें

अंत में, आप देख सकते हैं कि Trademark(™)यूनिकोड वर्ण में 8482 कोड है और 153 नहीं:

select nchar(8482), nchar(153)

1
लेकिन आपके द्वारा उल्लेखित लेख में कोई "ASCII" शब्द नहीं है, वे केवल यूनिकोड और गैर-यूनिकोड वर्णों के बारे में बात कर रहे हैं और ट्रेडमार्क (™) जो आपने उपयोग किया था, यूनिकोड नहीं था।
10

16
"विस्तारित ASCII" एक बहुत ही अस्पष्ट शब्द है। यह देखने में अधिक सहायक होगा कि वास्तव में उपयोग किए जाने वाले 8-बिट एन्कोडिंग क्या है (क्या यह लोकेल / कोलाज सेटिंग पर आधारित है?)। मैं विंडोज कोड पृष्ठ 1252 का अनुमान लगा रहा हूं , जो वास्तव में ™ को चरित्र 153 के रूप में
बताता है

2
@sepupic मुझे लगता है कि आपको कोडपॉइंट और एनकोडिंग के बीच अंतर के बारे में अधिक पढ़ने की आवश्यकता है। विकिपीडिया मदद कर सकता है। "एक एन्कोडिंग मैप्स (संभवतः एक सबसेट) की श्रेणी जिसमें यूनिकोड कोड कुछ निश्चित आकार सीमा में मूल्यों के अनुक्रमों को इंगित करता है, कोड मान कहलाता है ।" 8482 ™ के लिए कोडपॉइंट है, जिसे Windows-1252 में \ x99 (153) के रूप में, MacRoman में \ xAA के रूप में, UTF-8 में \ xE2 \ x84 \ xA2 के रूप में एन्कोड किया जा सकता है, आदि
curiousdannii

7
127 से ऊपर 8-बिट वर्णों के साथ देखभाल की जानी चाहिए: 127 से ऊपर प्रत्येक कोड क्या प्रतिनिधित्व करता है और उपयोग में एन्कोडिंग के आधार पर बदल सकता है जो कि भिन्न होता है जिसके आधार पर उपयोग में है। कोडपेज में 1252 यूनिकोड 8482 को मैप किया जाता है। कोडपेज 850 में उस स्थान को 214 ( Ö) और आईएसओ -8859-1 (कभी-कभी लैटिन 1 कहा जाता है) में लिया जाता है, यह एक नियंत्रण कोड है जिसमें कोई मुद्रण योग्य प्रतिनिधित्व नहीं है। जब तक आप नहीं जानते कि आप हमेशा एक ही कोडपेज का उपयोग करेंगे तो यह ANSI वर्णों (127 या उससे कम) से चिपके रहना या यूनिकोड प्रकारों का उपयोग करना अधिक सुरक्षित है। कोडपेज 1252 SQL सर्वर में सबसे आम है लेकिन सर्वव्यापी से बहुत दूर है।
डेविड स्पिललेट

4
@ शिव पूरी तरह से न्यूनतम हर सॉफ्टवेयर डेवलपर, यूनिकोड और चरित्र सेट के बारे में सकारात्मक रूप से जानना चाहिए । ASCII कई एन्कोडिंग्स का एक उपसमूह है , और लगभग सभी एनकोडिंग में गैर-ASCII प्रतीक होते हैं और एक साथ यूनिकोड नहीं होते हैं। और यूनिकोड के पास कई अलग-अलग एनकोडिंग भी हैं (जैसे कि UTF-8, UTF-32, आदि)।
jpmc26

7

टिप्पणियों से, मैं मानता हूं कि "विस्तारित एएससीआईआई" वास्तव में बुरा शब्द है जिसका वास्तव में एक कोड पेज है जो कि ASCII द्वारा परिभाषित मानक 0-127 कोड बिंदु सीमा से परे 128-255 रेंज में वर्ण / कोड बिंदुओं को मैप करता है।

SQL सर्वर collations के माध्यम से कई कोड पेज का समर्थन करता है। गैर- ASCII वर्णों को तब तक varchar में संग्रहीत किया जा सकता है जब तक कि अंतर्निहित collation वर्ण का समर्थन करता है।

SQL सर्वर collation कोड पृष्ठ 1250 या अधिक होने पर '™' वर्ण को varchar / char कॉलम में संग्रहीत किया जा सकता है। क्वेरी सूची में ये सूचीबद्ध होंगे:

SELECT COLLATIONPROPERTY(name, 'CodePage') AS code_page, name, description
FROM sys.fn_helpcollations()
WHERE COLLATIONPROPERTY(name, 'CodePage') >= 1250
ORDER BY name;

लेकिन इनमें से केवल एक सबसेट भी '©' वर्ण का समर्थन करता है, इसलिए कॉलम कोलेशन को दोनों का समर्थन करने के लिए निम्नलिखित में से एक होना पड़ेगा:

SELECT COLLATIONPROPERTY(name, 'CodePage') AS code_page, name, description
FROM sys.fn_helpcollations()
WHERE COLLATIONPROPERTY(name, 'CodePage') IN(
    1250
    ,1251
    ,1252
    ,1253
    ,1254
    ,1255
    ,1256
    ,1257
    ,1258
)
ORDER BY name;

4

लेकिन varchar की परिभाषा कहती है, यह गैर-यूनिकोड स्ट्रिंग डेटा की अनुमति देता है । लेकिन ट्रेडमार्क (™) और पंजीकृत (®) प्रतीक यूनिकोड वर्ण हैं । क्या परिभाषा varchar datatype की संपत्ति का विरोध करती है?

हालांकि अन्य उत्तर गलत नहीं हैं, मुझे लगता है कि यह आधार शब्दावली में एक भ्रम को इंगित करने में मदद करेगा। मैंने इस उलझन के उदाहरण के रूप में प्रश्न के उपरोक्त उद्धरण में दो शब्दों पर जोर दिया है। जब SQL सर्वर प्रलेखन यूनिकोड और गैर-यूनिकोड डेटा की बात करता है , तो वे वर्णों के बारे में बात नहीं कर रहे हैं । वे बाइट दृश्यों की बात कर रहे हैं जो कुछ वर्णों का प्रतिनिधित्व करते हैं। यूनिकोड प्रकार (के बीच प्राथमिक अंतर , , , और पदावनत / बुराई ) और गैर-यूनिकोड प्रकार ( , , और पदावनत / बुराई ) क्या है प्रकार बाइट दृश्यों के वे स्टोर कर सकते हैं।NCHARNVARCHARXMLNTEXTCHARVARCHARTEXT

गैर-यूनिकोड प्रकार कई 8-बिट एन्कोडिंग में से एक को संग्रहीत करते हैं, जबकि यूनिकोड प्रकार एकल 16-बिट यूनिकोड एन्कोडिंग को स्टोर करते हैं: UTF-16 लिटिल एंडियन। जैसा कि अन्य उत्तरों ने उल्लेख किया है, कौन से वर्ण 8-बिट / गैर-यूनिकोड एन्कोडिंग में संग्रहीत किए जा सकते हैं, कोड पृष्ठ पर निर्भर करता है, जो कि Collation द्वारा निर्धारित किया जाता है। हालांकि अन्य लोगों ने नोट किया है कि "वर्ण" का बाइट मान कोड पृष्ठों पर भिन्न हो सकता है, जिस पर यह पाया जाता है, बाइट मान समान कोड पेज के भीतर भी भिन्न ईबीडीआईसी कोड पेजों में से एक के साथ भिन्न हो सकता है। 1252), जो केवल पुराने में पाया जाता है, को वास्तव में इस्तेमाल किया जाने वाला SQL सर्वर Collations नहीं होना चाहिए (अर्थात जिनके नाम शुरू होते हैं SQL_)।

इसलिए, परिभाषा सटीक है: गैर-यूनिकोड प्रकार में संग्रहीत करने के लिए आप जो भी वर्ण प्रबंधित कर सकते हैं, वे हमेशा 8-बिट होते हैं (भले ही वे संयोजन में दो 8-बिट मानों का उपयोग एक एकल "वर्ण" के रूप में करते हैं, जो कि डबल है- बाइट कैरेक्टर सेट / DBCS कोड पेज के लिए अनुमति देते हैं)। और यूनिकोड डेटाटिप्स हमेशा 16-बिट होते हैं, भले ही वे कभी-कभी दो 16-बिट मानों को एक एकल "वर्ण" (यानी एक सरोगेट जोड़ी जो बदले में एक पूरक चरित्र का प्रतिनिधित्व करते हैं) के रूप में उपयोग करते हैं।

और, SQL सर्वर 2019 के लिए UTF-8 एन्कोडिंग VARCHARऔर CHARडेटाटाइप्स का मूल रूप से समर्थन करने के कारण ,

VARCHARअब "गैर-यूनिकोड" के रूप में संदर्भित नहीं किया जा सकता है। इसलिए, सितंबर 2018 में SQL सर्वर 2019 के पहले सार्वजनिक बीटा के साथ शुरू करना चाहिए, हमें VARCHARSQL सर्वर 2019 से पहले संस्करणों के संदर्भ में बोलते हुए भी "8-बिट डेटाटाइप" के रूप में संदर्भित करना चाहिए। यह शब्दावली सभी 4 प्रकारों के लिए सही है जिन एनकोडिंग का उपयोग किया जा सकता है VARCHAR:

  1. विस्तारित ASCII
  2. डबल-बाइट कैरेक्टर सेट (DBCS)
  3. EBCDIC
  4. UTF-8 (यूनिकोड)

केवल TEXTडेटाटाइप (SQL सर्वर 2005 के रूप में पदावनत, इसलिए इसका उपयोग न करें) "गैर-यूनिकोड" है, लेकिन यह सिर्फ एक तकनीकीता है, और इसे "8-बिट डेटाटाइप" के रूप में संदर्भित करना सटीक है।

NVARCHAR, NCHARऔर NTEXT"UTF-16" या "16-बिट डेटाटाइप" के रूप में संदर्भित किया जा सकता है। ओरेकल, मेरा मानना ​​है, के लिए "यूनिकोड-ओनली" की शब्दावली का उपयोग करता है NVARCHAR, लेकिन यह स्पष्ट रूप से यूटीएफ -8 (एक यूनिकोड एन्कोडिंग) का उपयोग करने की संभावना से इनकार नहीं करता है, जो काम नहीं करेगा, इसलिए संभवतः इसके साथ छड़ी करना सबसे अच्छा है पहले दो विकल्प।

नए UTF-8 एनकोडिंग के विवरण के लिए, कृपया मेरी पोस्ट देखें:

SQL Server 2019 में मूल निवासी UTF-8 समर्थन: उद्धारकर्ता या गलत पैगंबर?

पुनश्च मैं धीरे-धीरे इन परिवर्तनों को प्रतिबिंबित करने के लिए SQL सर्वर प्रलेखन को अद्यतन करने के माध्यम से अपना काम कर रहा हूं।

PPS Microsoft ने पहले ही UTF-8 जानकारी के साथ कुछ पेज अपडेट किए हैं, जिसमें प्रश्न में संदर्भित चार और varchar प्रलेखन शामिल हैं। इसमें अब "गैर-यूनिकोड" वाक्यांश शामिल नहीं है। लेकिन यह सिर्फ एक FYI है; यह इस सवाल को नहीं बदलता है क्योंकि यह गैर-यूनिकोड एन्कोडिंग वाले पात्रों के बारे में है जिन्हें गलती से यूनिकोड-केवल माना गया था।


3

इस सवाल में एक केंद्रीय गलत धारणा है कि यूनिकोड क्या है। यूनिकोड चरित्र सेट, इसके साथ-साथ यूटीएफ -8 और यूटीएफ -16 जैसे एन्कोडिंग, कंप्यूटर में पाठ का प्रतिनिधित्व करने के कई तरीकों में से एक है, और जिसका उद्देश्य अन्य सभी चरित्र सेट और एन्कोडिंग को सुपरसेड करना है। यदि "गैर-यूनिकोड डेटा" का अर्थ "यूनिकोड में मौजूद वर्ण नहीं है", तो इस उत्तर में मेरे द्वारा उपयोग किए गए किसी भी पाठ को उस प्रकार में संग्रहीत नहीं किया जा सकता है, क्योंकि लैटिन वर्णमाला और सामान्य अंग्रेजी में उपयोग किए जाने वाले सामान्य विराम चिह्न के सभी अक्षर हैं। यूनिकोड में शामिल।

पाठ अभ्यावेदन मोटे तौर पर दो भागों में सोचा जा सकता है: एक चरित्र सेट एक संदर्भ चार्ट पर संख्याओं के लिए विभिन्न वर्णों (अक्षरों, अंकों, प्रतीकों, आदि) की मैपिंग करता है; और बिट्स के पैटर्न के रूप में उन संख्याओं का प्रतिनिधित्व करने वाला एन्कोडिंग (डिस्क पर, नेटवर्क कनेक्शन आदि)। यहां हम ज्यादातर पहले भाग से चिंतित हैं: कौन से वर्ण किसी विशेष वर्ण सेट के लिए चार्ट पर सूचीबद्ध हैं।

चूंकि यूनिकोड का उद्देश्य दुनिया के हर चरित्र के लिए नंबर (जिसे "कोड पॉइंट" कहते हैं) है, विकिपीडिया जैसे संदर्भ अक्सर संदर्भ जानकारी के मानक टुकड़े के रूप में एक चरित्र के यूनिकोड स्थिति को संदर्भित करेंगे। हालाँकि, इसका मतलब यह नहीं है कि अन्य वर्ण सेटों में भी उसी वर्ण के लिए मैपिंग नहीं है।

अभी भी उपयोग में सबसे पुराना और सरल चरित्र सेट (और एन्कोडिंग) में से एक ASCII है, जिसमें 128 विभिन्न पात्रों (0 से 127) के लिए मैपिंग है, क्योंकि यह प्रत्येक चरित्र को एन्कोड करने के लिए 7 बिट्स का उपयोग करता है। चूंकि यह कई उच्चारण पात्रों और सामान्य प्रतीकों को बाहर करता है, बाद में एन्कोडिंग 8 बिट्स का उपयोग करते हैं, और समान पहले 128 वर्णों को मैप करते हैं, जो कि पदों को 128 से 255 तक भरते हुए वर्ण में जोड़ते हैं। इनमें से उल्लेखनीय आईएसओ 8859-1 और आईएसओ 8859 मानक हैं। 15 , और Microsoft-विशिष्ट Windows कोड पृष्ठ 1252

इसलिए, MS SQL सर्वर पर वापस आने के लिए: एक "यूनिकोड स्ट्रिंग", जैसा कि एक nchar, nvarcharया ntextकॉलम में संग्रहीत है , यूनिकोड वर्ण सेट में मैप किए गए सभी वर्णों का प्रतिनिधित्व कर सकता है , क्योंकि यह डेटा को संग्रहीत करने के लिए एक यूनिकोड एन्कोडिंग का उपयोग करता है। एक "गैर-यूनिकोड स्ट्रिंग", जैसा कि एक , या कॉलम में संग्रहीत है char, केवल कुछ अन्य एन्कोडिंग में मैप किए गए वर्णों का प्रतिनिधित्व कर सकता है । आप जो कुछ भी गैर-यूनिकोड कॉलम में स्टोर कर सकते हैं, उसे यूनिकोड कॉलम में भी संग्रहीत किया जा सकता है, लेकिन इसके विपरीत नहीं।varchartext

यह जानने के लिए कि आप कौन से वर्ण संग्रहीत कर सकते हैं, आपको उपयोग में "कॉलेशन" को जानना होगा, जो यह बताता है कि Microsoft "कोड पृष्ठ" के रूप में क्या संदर्भित करता है, जैसा कि इस Microsoft संदर्भ पृष्ठ पर बताया गया है । आपके मामले में यह संभावना है कि आप बहुत सामान्य कोड पृष्ठ 1252 का उपयोग कर रहे हैं, जिसका मैंने पहले उल्लेख किया था।

आपके द्वारा उल्लिखित वर्ण यूनिकोड और कोड पृष्ठ 1252 दोनों में मौजूद हैं:

  • ट्रेडमार्क (™) यूनिकोड में 8482 की स्थिति में और CP1252 की स्थिति 153 पर दिखाई देता है
  • पंजीकृत (®), जैसा कि होता है, यूनिकोड और CP1252 दोनों में स्थिति 174 पर दिखाई देता है

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

@ पोक जैसा कि मैं उत्तर में आगे कहता हूं, मैं "एन्कोडिंग" का उपयोग कर रहा हूं ताकि "चार्ट पर मौजूद पदों के लिए पात्रों की मैपिंग" और "बिट्स के अनुक्रम के रूप में उन पदों का प्रतिनिधित्व" दोनों का प्रतिनिधित्व किया जा सके। शायद उपयोग करने के लिए एक बेहतर शब्द है, लेकिन मुझे यकीन नहीं है कि यह क्या होगा।
IMSoP

3
ठीक है, आप केवल अपनी परिभाषा के साथ "एन्कोडिंग" का उपयोग नहीं कर सकते। क्षमा करें कि यहां नाइटपैकिंग हो सकती है, लेकिन आप ऐसा नहीं कर सकते हैं कि एक उत्तर में "यूनिकोड क्या है" के बारे में एक केंद्रीय गलत धारणा है
प्रहार

2
IMSoP (और @poke): मैं एन्कोडिंग के अलावा कुछ और मतलब के लिए "एन्कोडिंग" का उपयोग करने के बारे में पूरी तरह से प्रहार से सहमत हूं, हालांकि IMSoP की दुविधा के लिए मुझे भी सहानुभूति है। मेरी प्राथमिकता यूनिकोड को एक ऐसे चरित्र सेट के रूप में संदर्भित करना है, जिसमें कई एन्कोडिंग हैं, जबकि आमतौर पर चरित्र सेट और एन्कोडिंग का उपयोग उस समय के 1-टू -1 संबंध सबसे अधिक (या शायद सभी?) होने के कारण किया जाता है।
सोलोमन रटज़की

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