В SQL nvarchar и ограничения типа varchar
все, у меня есть большой (неизбежный) динамический SQL-запрос. Из-за количества полей в критериях выбора строка, содержащая динамический SQL, растет более чем на 4000 символов. Теперь я понимаю, что существует 4000 max set для NVARCHAR(MAX), но глядя на выполненный SQL в Профилировщике сервера для оператора
DELARE @SQL NVARCHAR(MAX);
SET @SQL = 'SomeMassiveString > 4000 chars...';
EXEC(@SQL);
GO
кажется, работает(!?), для другого запроса, который также является большим, он выдает ошибку, которая связана с этим пределом 4000(!?), он в основном урезает все SQL после этого 4000 предел и оставляет меня с синтаксической ошибкой. Несмотря на это в профилировщике, он показывает этот динамический SQL-запрос в полное(!?).
что именно здесь происходит, и я должен просто преобразовать эту переменную @SQL в VARCHAR и продолжить ее?
Спасибо за ваше время.
Ps. Также было бы неплохо иметь возможность распечатать более 4000 символов, чтобы посмотреть на эти большие запросы. Следующее ограничено до 4000
SELECT CONVERT(XML, @SQL);
PRINT(@SQL);
есть ли другой хороший способ?
4 ответов:
я понимаю, что есть 4000 Макс набор для
NVARCHAR(MAX)ваше понимание является неправильным.
nvarchar(max)может хранить до (и за пределами иногда) 2 ГБ данных (1 миллиард двухбайтовых символов).с nchar и nvarchar в книгах онлайн грамматика
nvarchar [ ( n | max ) ]The
|символ означает, что эти альтернативы. т. е. вы указываете илиnили буквальномmax.если вы решите указать конкретный
nтогда это должно быть между 1 и 4000, но с помощьюmaxопределяет его как тип данных большого объекта (замена дляntext, который является устаревшим).на самом деле в SQL Server 2008 кажется, что для переменная предел 2GB может быть превышен на неопределенный срок при условии достаточного пространства в
tempdb(показано здесь)относительно других частей ваш вопрос
усечение при объединении зависит от типа данных.
varchar(n) + varchar(n)будет усекаться на 8000 символов.nvarchar(n) + nvarchar(n)отсекает на 4000 символов.varchar(n) + nvarchar(n)отсекает на 4000 символов.nvarcharимеет более высокий приоритет, так что в результатеnvarchar(4,000)[n]varchar(max)+[n]varchar(max)не будет усекать (дляvarchar(max)+varchar(n)не будет усекать (для varchar(max).varchar(max)+nvarchar(n)не будет усекать (для nvarchar(max).nvarchar(max)+varchar(n)сначала преобразоватьvarchar(n)вход вnvarchar(n)а затем выполните конкатенацию. если длинаvarchar(n)строка больше 4000 символов приведение будетnvarchar(4000)и произойдет усечение.типы данных строковые литералы
если вы используете
Nпрефикс и строка nvarchar(n) здесьn- это длина строки. Так чтоN'Foo'будет рассматриваться какnvarchar(3)например. Если строка длиннее 4000 символов, она будет рассматриваться какnvarchar(max)если вы не используете
Nпрефикс и строка varchar(n) здесьn- это длина строки. Если дольшеvarchar(max)для обоих, если длина строки равна нулю, то
nимеет значение 1.новые элементы синтаксиса.
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типы данных вместе или потому, что вы объединяете avarchar(4001 - 8000)строкуnvarcharвведенную строку (дажеnvarchar(max)).чтобы избежать второй проблемы, просто убедитесь, что все строковые литералы (или, по крайней мере, те, которые имеют длину в диапазоне 4001 - 8000) предваряются
N.To избегайте первой проблемы измените назначение с
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бит позволяет избежать проблем с символы, такие как<отображается как<.
Итак, если позже вниз по линии проблема в том, что у вас есть запрос, который больше допустимого размера (что может произойти, если он продолжает расти), вам придется разбить его на куски и выполнить строковые значения. Итак, допустим, у вас есть хранимая процедура следующим образом:
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
вы также можете использовать текст nvarchar. это означает, что вы должны просто иметь "N" перед своей массивной строкой, и все! никаких ограничений больше
DELARE @SQL NVARCHAR(MAX); SET @SQL = N'SomeMassiveString > 4000 chars...'; EXEC(@SQL); GO
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
Comments