SQL NVARCHAR और VARCHAR सीमाएँ


100

सब, मेरे पास एक बड़ी (अपरिहार्य) गतिशील SQL क्वेरी है। चयन मानदंड में फ़ील्ड की संख्या के कारण गतिशील SQL युक्त स्ट्रिंग 4000 वर्णों से अधिक बढ़ रहा है। अब, मैं समझता हूँ कि NVARCHAR(MAX)कथन के लिए सर्वर प्रोफाइलर में निष्पादित SQL को देखने के लिए एक 4000 अधिकतम सेट है

DELARE @SQL NVARCHAR(MAX);
SET @SQL = 'SomeMassiveString > 4000 chars...';
EXEC(@SQL);
GO

एक और क्वेरी के लिए काम करने लगता है (?), यह एक बड़ी त्रुटि है जो इस 4000 सीमा (!) के साथ जुड़ा हुआ है, यह मूल रूप से इस 4000 सीमा के बाद SQL के सभी को चलाता है और मुझे एक सिंटैक्स त्रुटि के साथ छोड़ देता है। प्रोफाइलर में इसके बावजूद, यह इस गतिशील SQL क्वेरी को पूर्ण (?) में दिखा रहा है ।

वास्तव में यहाँ क्या हो रहा है और क्या मुझे इस @ SQL वैरिएचर को VARCHAR में परिवर्तित करना चाहिए और इसके साथ चलना चाहिए?

आपके समय के लिए धन्यवाद।

Ps। इन बड़े प्रश्नों को देखने के लिए 4000 से अधिक वर्णों का प्रिंट आउट लेना भी अच्छा होगा। निम्नलिखित 4000 तक सीमित हैं

SELECT CONVERT(XML, @SQL);
PRINT(@SQL);

क्या कोई और अच्छा तरीका है?


3
मैक्स 4000 सीमा का पर्याय नहीं है, इसका 1..4000 या मैक्स
एलेक्स के।

आपने C # dll के साथ प्रश्न को क्यों टैग किया है और स्विपन की स्थापना यह केवल एक Sql सर्वर प्रश्न है
HatSoft

संपादित।
हाजिर करने

PRINT 4000 अक्षरों (यूनिकोड के लिए) या 8000 वर्णों (एकल बाइट एन्कोडिंग के लिए) पर पहुंच जाएगा। मुझे संदेह है कि यहाँ भ्रम का स्रोत है।
Redcalx

जवाबों:


235

मैं समझता हूं कि इसके लिए 4000 अधिकतम सेट है NVARCHAR(MAX)

आपकी समझ गलत है। nvarchar(max)स्टोर कर सकते हैं (और कभी-कभी परे) 2GB डेटा (1 बिलियन डबल बाइट वर्ण)।

से nchar और nvarchar में पुस्तकें ऑनलाइन व्याकरण है

nvarchar [ ( n | max ) ]

|चरित्र का मतलब है इन विकल्प हैं। यानी आप या तो शाब्दिक रूप से निर्दिष्ट करते हैंnmax

यदि आप एक विशिष्ट निर्दिष्ट करने के लिए चुनते हैं nतो यह 1 और 4,000 के बीच होना चाहिए, लेकिन maxइसे एक बड़े ऑब्जेक्ट डेटाटाइप ( ntextजिसके लिए पदावनत किया गया है) के रूप में परिभाषित करता है ।

वास्तव में SQL Server 2008 में ऐसा लगता है कि एक चर के लिए 2GB की सीमा अनिश्चित काल के लिए पर्याप्त हो सकती है tempdb( यहाँ दिखाया गया है )

आपके प्रश्न के अन्य भागों के बारे में

जब संघनन डेटटाइप पर निर्भर करता है तो ट्रंकेशन।

  1. varchar(n) + varchar(n) 8,000 पात्रों पर छंटनी करेगा।
  2. nvarchar(n) + nvarchar(n) 4,000 पात्रों पर छंटनी करेगा।
  3. varchar(n) + nvarchar(n)4,000 पात्रों पर छंटनी करेगा। nvarcharइसका परिणाम अधिक हैnvarchar(4,000)
  4. [n]varchar(max)+ [n]varchar(max)छोटा नहीं होगा (<2GB के लिए)।
  5. varchar(max)+ varchar(n)छोटा नहीं होगा (<2GB के लिए) और परिणाम को टाइप किया जाएगा varchar(max)
  6. varchar(max)+ nvarchar(n)छोटा नहीं होगा (<2GB के लिए) और परिणाम को टाइप किया जाएगा nvarchar(max)
  7. nvarchar(max)+ varchar(n)सबसे पहले varchar(n)इनपुट को रूपांतरित करेगा nvarchar(n)और फिर संघनन करेगा। यदि varchar(n)स्ट्रिंग की लंबाई 4,000 वर्णों से अधिक है, तो कलाकारों को हो जाएगा nvarchar(4000)और छंटनी होगी

स्ट्रिंग शाब्दिक के डेटाटिप्स

यदि आप Nउपसर्ग का उपयोग करते हैं और स्ट्रिंग <= 4,000 वर्ण लंबा है तो इसे टाइप किया जाएगा nvarchar(n)जहां nस्ट्रिंग की लंबाई है। तो उदाहरण के लिए N'Foo'इलाज किया जाएगा nvarchar(3)। यदि स्ट्रिंग 4,000 वर्णों से अधिक लंबी है तो इसे माना जाएगाnvarchar(max)

यदि आप Nउपसर्ग का उपयोग नहीं करते हैं और स्ट्रिंग <= 8,000 वर्ण लंबा है तो इसे टाइप किया जाएगा varchar(n)जहां nस्ट्रिंग की लंबाई है। अगर लंबे समय के रूप मेंvarchar(max)

उपरोक्त दोनों के लिए यदि स्ट्रिंग की लंबाई शून्य है तो n1 पर सेट किया जाता है।

नए वाक्यविन्यास तत्व।

1.CONCAT समारोह यहाँ मदद नहीं करता है

DECLARE @A5000 VARCHAR(5000) = REPLICATE('A',5000);

SELECT DATALENGTH(@A5000 + @A5000), 
       DATALENGTH(CONCAT(@A5000,@A5000));

उपर्युक्त तरीकों के दोनों तरीकों के लिए उपरोक्त रिटर्न 8000 है।

2. सावधानी बरतें+=

DECLARE @A VARCHAR(MAX) = '';

SET @A+= REPLICATE('A',5000) + REPLICATE('A',5000)

DECLARE @B VARCHAR(MAX) = '';

SET @B = @B + REPLICATE('A',5000) + REPLICATE('A',5000)


SELECT DATALENGTH(@A), 
       DATALENGTH(@B);`

रिटर्न

-------------------- --------------------
8000                 10000

ध्यान दें कि @Aट्रंकेशन का सामना करना पड़ा।

आप जिस समस्या का सामना कर रहे हैं, उसे कैसे हल करें।

आपको ट्रेंक्यूशन हो रहा है क्योंकि आप maxएक साथ दो गैर डेटाैटिप्स को समेट रहे हैं या क्योंकि आप एक varchar(4001 - 8000)स्ट्रिंग को nvarcharटाइप किए गए स्ट्रिंग (यहां तक ​​कि nvarchar(max)) के लिए संक्षिप्त कर रहे हैं ।

दूसरे मुद्दे से बचने के लिए बस सुनिश्चित करें कि सभी स्ट्रिंग शाब्दिक (या कम से कम 4001 - 8000 रेंज में लंबाई वाले) पूर्वनिर्धारित हैं N

पहले मुद्दे से बचने के लिए असाइनमेंट को बदलें

DECLARE @SQL NVARCHAR(MAX);
SET @SQL = 'Foo' + 'Bar' + ...;

सेवा

DECLARE @SQL NVARCHAR(MAX) = ''; 
SET @SQL = @SQL + N'Foo' + N'Bar'

ताकि एक NVARCHAR(MAX)शुरू से ही संघ में शामिल हो (प्रत्येक सहमति का परिणाम भी NVARCHAR(MAX)यही होगा)

देखने पर छंटनी से बचना

सुनिश्चित करें कि आपके पास "ग्रिड टू रिजल्ट" मोड चयनित है तो आप उपयोग कर सकते हैं

select @SQL as [processing-instruction(x)] FOR XML PATH 

SSMS विकल्प आपको XMLपरिणामों के लिए असीमित लंबाई निर्धारित करने की अनुमति देते हैं । processing-instructionबिट जैसे पात्रों के साथ मुद्दों से बचा जाता <के रूप में दिखने &lt;


2
@ किलकरम - आपको nvarchar(4000)रास्ते में एक अंतर्निहित कलाकार मिल सकता है । यदि एक स्ट्रिंग शाब्दिक 4,000 से कम वर्ण है तो इसे माना जाता है nvarchar(x)। इसका एक और nvarchar(x)महत्व यह है कि ऊपर उठने के बजाय और कम हो जाएगाnvarchar(max)
मार्टिन स्मिथ

2
@ किलकरम - आप शायद मेरी पहली टिप्पणी के अनुसार छंटनी कर रहे हैं। असाइनमेंट को बदलने का प्रयास करें DECLARE @SQL NVARCHAR(MAX) = ''; SET @SQL = @SQL + ताकि NVARCHAR(MAX)ए कॉन्फैक्शन में शामिल हो।
मार्टिन स्मिथ

2
@Killercam - संभवतः आपके पास 4,000 और 8,000 वर्णों के बीच एक स्ट्रिंग है। Nउपसर्ग के साथ कि nvarchar(max)इसे बिना इलाज किया जाएगा, तब माना जाएगा कि जब आप एकvarchar(n)nvarchar(4000)nvarchar
मार्टिन स्मिथ

3
मैं इस जवाब से
मुग्ध

1
बहुत बढ़िया जवाब। बहुत बहुत धन्यवाद!
जॉन बेल

6

ठीक है, इसलिए यदि बाद में लाइन के नीचे समस्या यह है कि आपके पास एक क्वेरी है जो स्वीकार्य आकार से अधिक है (जो हो सकता है अगर यह बढ़ती रहती है) तो आप इसे विखंडू में तोड़कर स्ट्रिंग मानों को निष्पादित करने जा रहे हैं। तो, मान लें कि आपके पास निम्न की तरह संग्रहीत प्रक्रिया है:

CREATE PROCEDURE ExecuteMyHugeQuery
    @SQL VARCHAR(MAX) -- 2GB size limit as stated by Martin Smith
AS
BEGIN
    -- Now, if the length is greater than some arbitrary value
    -- Let's say 2000 for this example
    -- Let's chunk it
    -- Let's also assume we won't allow anything larger than 8000 total
    DECLARE @len INT
    SELECT @len = LEN(@SQL)

    IF (@len > 8000)
    BEGIN
        RAISERROR ('The query cannot be larger than 8000 characters total.',
                   16,
                   1);
    END

    -- Let's declare our possible chunks
    DECLARE @Chunk1 VARCHAR(2000),
            @Chunk2 VARCHAR(2000),
            @Chunk3 VARCHAR(2000),
            @Chunk4 VARCHAR(2000)

    SELECT @Chunk1 = '',
           @Chunk2 = '',
           @Chunk3 = '',
           @Chunk4 = ''

    IF (@len > 2000)
    BEGIN
        -- Let's set the right chunks
        -- We already know we need two chunks so let's set the first
        SELECT @Chunk1 = SUBSTRING(@SQL, 1, 2000)

        -- Let's see if we need three chunks
        IF (@len > 4000)
        BEGIN
            SELECT @Chunk2 = SUBSTRING(@SQL, 2001, 2000)

            -- Let's see if we need four chunks
            IF (@len > 6000)
            BEGIN
                SELECT @Chunk3 = SUBSTRING(@SQL, 4001, 2000)
                SELECT @Chunk4 = SUBSTRING(@SQL, 6001, (@len - 6001))
            END
              ELSE
            BEGIN
                SELECT @Chunk3 = SUBSTRING(@SQL, 4001, (@len - 4001))
            END
        END
          ELSE
        BEGIN
            SELECT @Chunk2 = SUBSTRING(@SQL, 2001, (@len - 2001))
        END
    END

    -- Alright, now that we've broken it down, let's execute it
    EXEC (@Chunk1 + @Chunk2 + @Chunk3 + @Chunk4)
END

2

आप नर्वचर टेक्स्ट का भी उपयोग करते हैं। इसका मतलब है कि आपको अपने बड़े पैमाने पर स्ट्रिंग से पहले बस "एन" होना चाहिए और यही है! अब कोई सीमा नहीं

DELARE @SQL NVARCHAR(MAX);
SET @SQL = N'SomeMassiveString > 4000 chars...';
EXEC(@SQL);
GO

3
यह पूरी तस्वीर नहीं है ... यदि आप एन उपसर्ग का उपयोग करते हैं और स्ट्रिंग <= 4,000 वर्ण लंबा है तो इसे टाइप किया जाएगा nvarchar(n)जहां n स्ट्रिंग की लंबाई है। इसलिए N'Foo 'को nvarchar(3)उदाहरण के रूप में माना जाएगा । यदि स्ट्रिंग 4,000 वर्णों से अधिक लंबी है तो इसे माना जाएगा nvarchar(max)। यदि आप N उपसर्ग का उपयोग नहीं करते हैं और स्ट्रिंग <= 8,000 वर्ण लंबा है तो इसे टाइप किया जाएगा varchar(n)जहां n स्ट्रिंग की लंबाई है। अगर लंबे समय के रूप में varchar(max)। उपरोक्त दोनों के लिए यदि स्ट्रिंग की लंबाई शून्य है तो n 1 पर सेट है
MoonKnight

1

स्वीकार किए गए उत्तर ने मेरी मदद की, लेकिन मैं मामले के बयानों को शामिल करते हुए विचरण करता रहा। मुझे पता है कि ओपी के सवाल में केस स्टेटमेंट शामिल नहीं है, लेकिन मुझे लगा कि मेरे जैसे अन्य लोगों के लिए यहां पोस्ट करना मददगार होगा, जो केस स्टेटमेंट से जुड़े लंबे डायनामिक एसक्यूएल स्टेटमेंट बनाने के लिए संघर्ष करते हुए यहां समाप्त हो गए।

स्ट्रिंग सहमति के साथ केस स्टेटमेंट का उपयोग करते समय स्वीकार किए गए उत्तर में वर्णित नियम स्वतंत्र रूप से केस स्टेटमेंट के प्रत्येक सेक्शन पर लागू होते हैं।

declare @l_sql varchar(max) = ''

set @l_sql = @l_sql +
case when 1=1 then
    --without this correction the result is truncated
    --CONVERT(VARCHAR(MAX), '')
 +REPLICATE('1', 8000)
 +REPLICATE('1', 8000)
end

print len(@l_sql)

0
declare @p varbinary(max)
set @p = 0x
declare @local table (col text)

SELECT   @p = @p + 0x3B + CONVERT(varbinary(100), Email)
 FROM tbCarsList
 where email <> ''
 group by email
 order by email

 set @p = substring(@p, 2, 100000)

 insert @local values(cast(@p as varchar(max)))
 select DATALENGTH(col) as collen, col from @local

result collen > 8000, length col value is more than 8000 chars
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.