Использование VARCHAR (MAX) с конкатенацией строк в SQL Server 2005 - PullRequest
4 голосов
/ 28 декабря 2010

Пользователь одной из наших баз данных пытается отправить запрос UPDATE в базу данных SQL Server 2005, и текст неожиданно усекается.

Усеченное поле имеет значение VARBINARY (MAX) и используется для хранения текста HTML.

Запрос примерно:

UPDATE Story 
SET mainText = CONVERT (VARBINARY (MAX), '[...5000 chars of text...]' 
    + char(47) + char(47)
    + '[...3000 chars of text...]'
    + char(47) + char(47)
    + '[...5000 chars of text...]') 
WHERE storyId = 123456

После некоторых экспериментов я обнаружил, что при удалении конкатенации строк запрос работает, как и ожидалось, и поле не усекается.

Мне удалось обойти ограничение и сохранить конкатенацию, обернув каждую отдельную строку в CAST в VARCHAR (MAX), поэтому есть опция, если пользователь считает необходимым использовать char ().

Что я думаю, что происходит , так это то, что всякий раз, когда используется оператор конкатенации, происходит неявное преобразование в VARCHAR, и это неявное преобразование ограничивается VARCHAR (8000) вместо VARCHAR (MAX) , Таким образом, еще до того, как строка отправляется в функцию CONVERT, она уже усекается до 8000 символов.

Если я прав, есть ли способ изменить это поведение?

Если нет способа изменить поведение, есть ли другой способ решения проблемы, кроме CAST?

Ответы [ 5 ]

10 голосов
/ 28 декабря 2010

Вам нужно CAST первую строку first .

CONVERT (VARBINARY (MAX), '[...5000 chars of text...]')
    + char(47) + char(47)
    + '[...3000 chars of text...]'
    + char(47) + char(47)
    + '[...5000 chars of text...]'

Раньше внутренний текст никогда не превышал 8000 байт. Тогда ты КЕЙСТИНГ. Слишком поздно.

'[...5000 chars of text...]') 
    + char(47) + char(47)
    + '[...3000 chars of text...]'
    + char(47) + char(47)
    + '[...5000 chars of text...]' 

Для более полного прохождения «почему», пожалуйста, смотрите мой ответ здесь «Для Nvarchar (Max) я получаю только 4000 символов в TSQL?»

2 голосов
/ 28 декабря 2010

По моему опыту 1) вам нужно только наложить самый левый предмет на varchar (макс.):

UPDATE Story 
SET mainText = CONVERT (VARBINARY (MAX), '[...5000 chars of text...]') 
    + char(47) + char(47)
    + '[...3000 chars of text...]'
    + char(47) + char(47)
    + '[...5000 chars of text...]' 
WHERE storyId = 123456

2) Вы можете предоставить весь текст в виде одного строкового литерала, не путайте ограничения для результатов запроса 8192 символа на столбец или оператора PRINT 8000 символов. Вам не нужно экранировать символы '/' как char (...). Единственное, что вам нужно сделать, это дублировать встроенные апострофы.

1 голос
/ 25 июня 2014

Решение

Создать несколько SET Операторы, которые добавляют менее 8000 байтов каждое. SQL будет автоматически расширять размер строки во время конкатенации.

Пример

declare @SQLStatement nvarchar(Max)
SET @SQLStatement = '[...first block of text...]'
SET @SQLStatement = @SQLStatement + '[...next block of text...]'
...

Фон

У меня была такая же проблема, только ничего из вышеперечисленного не сработало. В моем случае код использовал nvarchar (max). Я попытался преобразовать первую строку явно в nvarchar (max), но это не помогло. В моем случае было добавлено много строк, и их было очень легко разорвать. Имейте в виду, что nchar берет 2x char. В нашем случае разработчик перешел с char на nchar, что и вызвало нашу ошибку и подтолкнуло нас к 8000-байтовому фронту. У нас было чуть более 4000 символов (я не говорю, что это хорошая практика :), и переключение на nchar удваивает его, а затем мы превышаем предел 8000 символов.

Почему

Почему это работает? Я уверен, что некоторые главы SQL могли бы сказать нам, но я полагаю, что это связано с тем, как SQL будет динамически распределять пространство для nvarchar (max) в зависимости от необходимости. По какой-то причине он не может сделать это в пределах одного оператора SET. Но если вы их разбиваете, то с каждой новой конкатенацией он переоценивает и выделяет необходимое пространство, когда обнаруживает, что вы превысили предел 8000.

0 голосов
/ 28 декабря 2010

Ваше усечение происходит, потому что сначала выполняется конкатенация строк [...5000 chars of text...]' + char(47) + char(47) + '[...3000 chars of text...]' + char(47) + char(47) + '[...5000 chars of text...]'), а затем выполняется преобразование в VARBINARY (MAX).

Сначала необходимо преобразовать каждую строку в VARBINARY (MAX), а затем выполнить конкатенацию

UPDATE Story 
SET mainText = 
      CONVERT (VARBINARY (MAX), '[...5000 chars of text...]' )
    + CONVERT (VARBINARY (MAX), char(47) + char(47))
    + CONVERT (VARBINARY (MAX), '[...3000 chars of text...]')
    + CONVERT (VARBINARY (MAX), char(47) + char(47)
    + CONVERT (VARBINARY (MAX), '[...5000 chars of text...]') )
WHERE storyId = 123456
0 голосов
/ 28 декабря 2010

Вы должны попытаться сделать CONVERT для каждой строки, которую вы объединяете.Или вы можете разделить запрос на несколько UPDATE (при условии, что основной текст столбца VARBINARY(MAX)).

UPDATE Story 
SET mainText = CONVERT (VARBINARY (MAX), '[...5000 chars of text...]' )
               + char(47) + char(47)
               + CONVERT (VARBINARY (MAX),'[...3000 chars of text...]')
               + char(47) + char(47)
               + CONVERT (VARBINARY (MAX),'[...5000 chars of text...]') 
WHERE storyId = 123456

или

UPDATE Story 
SET mainText = '[...5000 chars of text...]'
WHERE storyId = 123456

UPDATE Story 
SET mainText = maintext + char(47) + char(47) + '[...3000 chars of text...]'
WHERE storyId = 123456

UPDATE Story 
SET mainText = maintext + char(47) + char(47) + '[...5000 chars of text...]'
WHERE storyId = 123456
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...