तालिका पंक्ति में "CO2" को "CO₂" अपडेट नहीं कर सकते


19

इस तालिका को देखते हुए:

CREATE TABLE test (
    id INT NOT NULL,
    description NVARCHAR(100) COLLATE Modern_Spanish_CI_AS NOT NULL
);
INSERT INTO test (id, description) VALUES (1, 'CO2');

मुझे एहसास हुआ कि मैं एक टाइपोग्राफिक समस्या ठीक नहीं कर सकता:

SELECT * FROM test WHERE id = 1;
UPDATE test SET description = 'CO₂' WHERE id = 1;
SELECT * FROM test WHERE id = 1;

क्योंकि अपडेट मेल खाता है लेकिन इसका कोई प्रभाव नहीं है:

id          description
----------- -----------
1           CO2

(1 affected rows)

(1 affected rows)

id          description
----------- -----------
1           CO2

(1 affected rows)

यह ऐसा है एसक्यूएल सर्वर है कि निर्धारित करता है, के बाद से है स्पष्ट रूप से सिर्फ एक छोटे से है 2 तो यह इसे बदलने के लायक नहीं है अंतिम मूल्य में परिवर्तन नहीं होगा।

क्या कोई इस पर कुछ प्रकाश डाल सकता है और शायद वर्कअराउंड (एक मध्यस्थ मूल्य को अद्यतन करने के अलावा) का सुझाव दे सकता है?


1
अलवारो: यदि आप इस व्यवहार के बारे में अधिक जानना चाहते हैं, तो यह समझने के लिए कि यह क्यों हो रहा है, कृपया दो लिंक देखें, जिन्हें मैंने अपने उत्तर के निचले हिस्से में जोड़ा था।
सोलोमन रटज़स्की

जवाबों:


29

सबस्क्रिप्ट 2 varchar वर्ण सेट का हिस्सा नहीं है (किसी भी टकराव में, न कि केवल Modern_Spanish)। इसलिए इसे नवरचट स्थिरांक बनाएं:

UPDATE test SET description = N'CO₂' WHERE id = 1;

1
न केवल मैंने मूल्य तय किया है, मैं यह भी समझ गया हूं कि यह पहली जगह में कैसे मिला। धन्यवाद!
अल्वारो गोंजालेज

2
@ GlvaroGonzález और gbn: बस स्पष्ट होने के लिए, "सब्स्क्रिप्‍ट 2" डिफ़ॉल्ट रूप से विचाराधीन डेटाबेस के कोलाज़ द्वारा निर्दिष्ट कोड पृष्ठ में उपलब्ध नहीं है, जो कि स्ट्रिंग शाब्दिक और चर के लिए उपयोग किया जाने वाला कोलाज है, न कि कॉलम का कोलाज (हालाँकि दोनों के लिए) एक ही कोड पेज का उपयोग किया जा सकता है)। हालांकि, "सदस्यता 2" कोरियाई Collations के माध्यम से कोड पृष्ठ 949 में उपलब्ध है। यहाँ मदद नहीं करेगा, लेकिन सिर्फ FYI करें। मेरे पास मेरे उत्तर में विवरण और एक उदाहरण है ।
सोलोमन रटज़की

21

@ लोगों ने पहले ही मूल कारण और तय कर दिया था, लेकिन जो व्यवहार आप देख रहे हैं उसका विशिष्ट कारण यह है:

  1. आप VARCHARशाब्दिक ( Nउपसर्ग के NVARCHARसाथ स्ट्रिंग ) के बजाय एक शाब्दिक (कोई उपसर्ग) का उपयोग कर रहे हैं N, इसलिए यूनिकोड वर्ण में परिवर्तित हो जाएगा VARCHAR
  2. VARCHARएक 8-बिट एन्कोडिंग है, जो ज्यादातर मामलों में, प्रति वर्ण एक बाइट है, लेकिन प्रति चरित्र दो बाइट्स भी हो सकता है। दूसरी ओर, NVARCHAR16-बिट एन्कोडिंग (UTF-16 लिटिल एंडियन) है जो कि प्रति वर्ण दो बाइट्स या चार बाइट्स है।
  3. मैपिंग वर्णों के लिए उपयोग करने के लिए उपलब्ध बाइट्स की संख्या में अंतर के कारण, 8 बिट एन्कोडिंग, उनके स्वभाव से, मैप किए जा सकने वाले वर्णों की संख्या में बहुत अधिक सीमित हैं। VARCHARसिंगल-बाइट कैरेक्टर सेट्स (उनमें से अधिकांश) के लिए 256 वर्णों तक और डबल-बाइट कैरेक्टर सेट्स (इनमें से केवल कुछ) के लिए 65,536 वर्णों तक का डेटा है। दूसरी ओर, NVARCHARडेटा सिर्फ 1.1 मिलियन यूनिकोड वर्णों (हालांकि अभी 250k अंडर मैप्ड है) पर मैप कर सकता है।
  4. 8-बिट / VARCHARडेटा के साथ किए जा सकने वाले मैपिंग की सीमित संख्या के कारण , वर्णों के विभिन्न समूह (भाषा / संस्कृति के आधार पर) एकाधिक "कोड पेज" (अर्थात वर्ण सेट) में फैले हुए हैं
  5. प्रत्येक Collation निर्दिष्ट करता है कि VARCHARडेटा के लिए कौन सा कोड पृष्ठ, यदि कोई हो, ( NVARCHARसभी वर्ण है)
  6. स्ट्रिंग स्ट्रिंग शाब्दिक या चर NVARCHAR(यानी यूनिकोड / यूटीएफ -16 / सभी वर्ण) को VARCHAR(कोड पृष्ठ पर आधारित वर्ण सेट जो कि अधिकांश कोलाज़ों में निर्दिष्ट है ) से परिवर्तित करते समय , डेटाबेस के डिफ़ॉल्ट Collation का उपयोग किया जाता है
  7. यदि रूपांतरण के लिए उपयोग किए जा रहे Collation के कोड पृष्ठ में समान वर्ण नहीं है, लेकिन इसमें "सर्वश्रेष्ठ फिट" मैपिंग है, तो "सर्वश्रेष्ठ फ़िट" मैपिंग का उपयोग किया जाएगा।
  8. यदि रूपांतरण के लिए उपयोग किए जा रहे Collation के कोड पृष्ठ में समान वर्ण नहीं है या "सर्वश्रेष्ठ फिट" मैपिंग है, तो डिफ़ॉल्ट "प्रतिस्थापन" वर्ण का उपयोग किया जाएगा (सबसे अधिक ?)।

तो, क्या आप देख रहे हैं एक है NVARCHARकरने के लिए VARCHARकारण लापता करने के लिए रूपांतरण Nस्ट्रिंग शाब्दिक पर उपसर्ग। और, डेटाबेस के लिए डिफ़ॉल्ट Collation के कोड पृष्ठ में सटीक समान वर्ण शामिल नहीं है, लेकिन एक "सर्वश्रेष्ठ फिट" मैपिंग पाई गई, यही वजह है कि आपको 2इसके बजाय मिल रहा है ?

आप निम्नलिखित सरल परीक्षण करके इस आशय को देख सकते हैं:

SELECT '₂', N'₂';

यह दिखाता है:

2    ₂

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

महत्वपूर्ण: कृपया ध्यान रखें कि रूपांतरण तब होता है जब स्ट्रिंग शाब्दिक व्याख्या की जा रही है, जो कि कॉलम में संग्रहीत होने से पहले है। इसका मतलब यह है कि भले ही कॉलम उस चरित्र को पकड़ सकता है, यह पहले से ही कुछ और में बदल गया होगा, डेटाबेस के डिफ़ॉल्ट Collation के आधार पर, सभी Nउस स्ट्रिंग शाब्दिक पर उपसर्ग को छोड़ने के कारण । और यह वही है जो आप अनुभव कर रहे हैं (या थे)।

उदाहरण के लिए, यदि आपके डेटाबेस का डिफ़ॉल्ट Collation कोरियाई Collations (चार डबल-बाइट कैरेक्टर सेट्स में से एक) में से एक होता, तो आपको यह समस्या नहीं दिखाई देती क्योंकि "Subscript 2" का चरित्र उस वर्ण में उपलब्ध होता है सेट (कोड पृष्ठ ९ ४ ९)। देखने के लिए निम्न परीक्षण का प्रयास करें (यह डेटाबेस के डिफ़ॉल्ट Collation के बजाय कॉलम के Collation का उपयोग करता है क्योंकि यह दिखाना आसान है):

CREATE TABLE #TestChar
(
    [8bit_Latin1_General-1252] VARCHAR(2) COLLATE Latin1_General_100_CI_AS_SC,
    [8bit_Korean-949] VARCHAR(2) COLLATE Korean_100_CI_AS_SC,
    [UTF16LE_Latin1_General-1252] NVARCHAR(2) COLLATE Latin1_General_100_CI_AS_SC
);

INSERT INTO #TestChar VALUES (N'₂', N'₂', N'₂');

SELECT * FROM #TestChar;

यह दिखाता है:

8bit_Latin1_General-1252    8bit_Korean-949    UTF16LE_Latin1_General-1252
2                           ₂                  ₂

जैसा कि आप देख सकते हैं, डेटा के Modern_Spanishलिए कोड 1, 1251 (समान कोड पेज जिसका उपयोग कोलाज़ उपयोग करता है) में लैटिन 1_जनरल कोलाजेशन, VARCHARएक सटीक मिलान नहीं है, लेकिन उनके पास "सबसे अच्छा फिट" मैपिंग है (जो आप देख रहे हैं। )। BUT, कोरियाई Collations, जो VARCHARडेटा के लिए कोड पृष्ठ 949 का उपयोग करते हैं, का "Subscript 2" वर्ण के लिए सटीक मिलान है।


आगे वर्णन करने के लिए, हम एक कोरियाई Collations के डिफ़ॉल्ट Collation के साथ एक नया डेटाबेस बना सकते हैं, और फिर उस प्रश्न में सटीक SQL चला सकते हैं:

CREATE DATABASE [TestKorean-949] COLLATE Korean_100_CI_AS_KS_WS_SC;
ALTER DATABASE [TestKorean-949] SET RECOVERY SIMPLE;
GO

USE [TestKorean-949];

CREATE TABLE test (
    id INT NOT NULL,
    description NVARCHAR(100) COLLATE Modern_Spanish_CI_AS NOT NULL
);
INSERT INTO test (id, description) VALUES (1, 'CO2');


SELECT * FROM test WHERE id = 1;
UPDATE test SET description = 'CO₂' WHERE id = 1;
SELECT * FROM test WHERE id = 1;

यह दिखाता है:

id  description
1   CO2


id  description
1   CO₂

अपडेट करें

जो लोग वास्तव में यहाँ क्या हो रहा है (यानी सभी विवरण के बारे में अधिक जानकारी प्राप्त करने में रुचि रखते हैं ) के लिए, कृपया मेरे द्वारा पोस्ट की गई दो-भाग की जांच देखें:

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