Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 nvarchar(max) и 8000 символов  [new]
beg_inner
Guest
поделитесь пожалуйста, если кто знает:
почему даже объявив переменную как varchar(max) может произойти обрезание до 8000 символов? мне пожаловались по этому поводу и я решила проверить.
declare @s varchar(max)
set @s = replicate('a', 5000) + replicate('b', 5000)

select len(@s)

интересно, что на моем сервере отработало как
-------
10000

попутно вопрос: почему нельзя было сразу set @s = replicate('a', 10000)?
когда проделала это, сразу мне обрезалось до 8000. но ок, свалила все на особенности replicate.

и вот меня пустили на тот сервер, где якобы обрезает.
проделала то же самое, и правда, выдалось 8000 как длина.
ок, я не сдаюсь, добавляю явную конвертацию:
set @s = cast('c' as varchar(max)) + replicate('a', 5000) + replicate('b', 5000)

и это даже на том загадочном сервере сработало, длина стала 10001.
вопрос: почему такое разное поведение (оба сервера 2005 со всеми сервиспаками)
и почему надо явно к типу приводить, почему недостаточно объявления переменной как varchar(max)?
8 дек 11, 20:17    [11732578]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
Alexandr Kr.
Member

Откуда: Украина, Харьков
Сообщений: 165
beg_inner,

Наверное потому что в случае
set @s = replicate('a'), 5000) + replicate('b', 5000)

применяется , то что указано в хелпе по ф-ии replicate
Returns the same type as string_expression
соответственно если сделать так
set @s = replicate(cast('a' as varchar(10000)), 5000) + replicate('b', 5000)
то все будет как ожидаалось
8 дек 11, 20:32    [11732630]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
Alexandr Kr.
Member

Откуда: Украина, Харьков
Сообщений: 165
beg_inner,

Сори за предыдущий комент. Ошибка там

Наверное потому что в случае
set @s = replicate('a'), 5000) + replicate('b', 5000)

применяется , то что указано в хелпе по ф-ии replicate
Returns the same type as string_expression
соответственно если сделать так
set @s = replicate(cast('a' as varchar(max)), 5000) + replicate('b', 5000)
то все будет как ожидаалось
8 дек 11, 20:33    [11732634]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
beg_inner
Guest
ок, но почему же на одном сервере
declare @s varchar(max)
set @s = replicate('a', 5000) + replicate('b', 5000)
select len(@s)

возвращает 10000, а на другом 8000?
хелп по replicate на обоих серверах одинаковый :) , а результат-то разный!!!
8 дек 11, 20:44    [11732681]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
Alexandr Kr.
Member

Откуда: Украина, Харьков
Сообщений: 165
beg_inner
ок, но почему же на одном сервере
declare @s varchar(max)
set @s = replicate('a', 5000) + replicate('b', 5000)
select len(@s)

возвращает 10000, а на другом 8000?
хелп по replicate на обоих серверах одинаковый :) , а результат-то разный!!!


Если именно ЭТОТ скрипт возвращает 10000, то у меня нет объяснения этому факту. Послежу за другими мнениями значит.
8 дек 11, 20:49    [11732697]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
Knyazev Alexey
Member

Откуда: Екб -> Мск
Сообщений: 10233
Блог
beg_inner
возвращает 10000, а на другом 8000?
хелп по replicate на обоих серверах одинаковый :) , а результат-то разный!!!


неявное преобразование!? ;)

declare @s varchar(max)
set @s = cast( replicate('a', 5000) as varchar(max) ) + cast( replicate('b', 5000) as varchar(max) )
select len(@s), datalength(@s)
8 дек 11, 20:52    [11732704]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
beg_inner
Guest
прикольно. т.е. и у вас обрезает, как на том сервере???
а у меня-то НЕТ!!!!
я как раз билась, чтоб воспроизвести, чтоб обрезало, но у меня именно что 10000!
что интересно сделано странного у вас и у них?
у меня все установки по умолчанию, только модель восстановления сменила сразу на симпл, у модел, т.к. мой сервер скажем так, домашний, живет на ноуте и используется для тестов с правами администратора...
8 дек 11, 20:53    [11732707]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
Alexandr Kr.
Member

Откуда: Украина, Харьков
Сообщений: 165
Knyazev Alexey
неявное преобразование!? ;)


Вот если неявное преобразование то непонятен такой момент. По таблице приоритетности типов данных varchar и varchar(max) имеют один и тот же приоритет. Но по факту получается что varchar(max) приоритенее чем varchar?
8 дек 11, 20:55    [11732710]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
beg_inner
Guest
Knyazev Alexey,
не поняла. если делать как у Вас, ок, явно преобразовали.
а если делать как у меня, то, как выше ответили, replicate мне отдаст varchar.
при присвоении varchаr-а varchar(max)-у, сервер должен преобразовывать или нет?
вернее так, какой из серверов ведет себя стандартно, который преобразует (вроде логично преобразовывать, я же явно указала, какого типа переменная) или который отдает упорно просто varchar? и что влияет на поведение сервера, какая настройка?
8 дек 11, 21:01    [11732730]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
gds
Member

Откуда: Железнодорожный
Сообщений: 1842
Блог
Доброго всем настроения! Заинтересовала тема...
И вот что обнаружил
declare @s varchar(max)
set @s = replicate('a', 5000) + replicate('b', 5000)
select len(@s)
GO

результат

--------------------
8000

(1 row(s) affected)
а
declare @s nvarchar(max)
set @s = replicate(N'a', 5000) + replicate(N'b', 5000)
select len(@s)
GO



--------------------
4000

(1 row(s) affected)

Мои предположения, скорее всего при неявном преобразовании varchar(max) и nvarchar(max) выбираются такими (минимально выделенная память), чтобы данные вместились на одну страницу. А вот если не будет хватать длинны, то скуль расширяет (выделяет) еще одну станицу для хранения...
8 дек 11, 21:14    [11732745]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
Knyazev Alexey
Member

Откуда: Екб -> Мск
Сообщений: 10233
Блог
beg_inner
Knyazev Alexey,
не поняла. если делать как у Вас, ок, явно преобразовали.
а если делать как у меня, то, как выше ответили, replicate мне отдаст varchar.
при присвоении varchаr-а varchar(max)-у, сервер должен преобразовывать или нет?
вернее так, какой из серверов ведет себя стандартно, который преобразует (вроде логично преобразовывать, я же явно указала, какого типа переменная) или который отдает упорно просто varchar? и что влияет на поведение сервера, какая настройка?


declare @s varchar(max)
set @s = cast( '' as varchar(max) ) + replicate('a', 5000) +  replicate('b', 5000) 
select len(@s)
8 дек 11, 21:19    [11732765]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
beg_inner
Guest
дико извиняюсь.
хотела завесить картинку, раз у всех 8000, а у меня 10000.
открыла сохраненный скрипт с тестами, у меня там не 5000, а 500.
хотя начинала точно с 10000, потом оно мне обрезало, я перешла на 5000,
потом еще всяко меняла tabletextinrowlimit и такое же про long type values,
короче, как-то 5000 плавно перешло в 500, в общем, и у меня 8000.

но тетка, которая мне жаловалась, что ей обрезает, она replicate не использовала совсем, она свои строки слепляла, но явно не преобразовывала. и ей обрезалось.
так что все же дело не в том, что отдает replicate, а в том, что сервер халтурит.
если я объявлю decimal(17,2) и туда присвою 1, это же не значит, что он его нагло преобразует в int и место под хранение урежет.
так что немного нечестно, если я присваиваю соединение строк и не конвертирую, выделять под них менее заявленного. прикол в том, что хватит конвертировать всего ОДНО из слагаемых в varchar(max) -- даже всего 1 символ, и другие слагаемые уже можно не конвертировать, он ничего обрезать не станет...
8 дек 11, 21:36    [11732803]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
beg_inner
Guest
а, ну вот постом выше как раз про то же. хватит конвертировать одного.
но еще раз, никто же не урезает 1 до int, если я ее присваиваю в переменную decimal(17,2)!
8 дек 11, 21:38    [11732807]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
locky
Member

Откуда: Харьков, Украина
Сообщений: 62034
читайте бол, там всё написано
select datalength(replicate(cast('8' as varchar(max)),163840))
--------------------
163840
8 дек 11, 21:45    [11732822]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
Че там говорить, если ещё перед выходом SQL2005 вышла книжка
одного уважаемого американского автора про SQL2005 beta,
в которой он утверждал, что в REPLICATE странный глюк - сохраняется
ограничение 8000 байт, хотя вроде как появился VARCHAR(MAX).
Всё это серьёзно, с подтверждающими скриптами...
Я начитался всего этого и тут на форуме с треском опозорился!
Мне мягко указали на явное преобразование аргумента REPLICATE.
А уже потом об этом и в BOL написали. Когда релиз вышел.

P.S. сейчас ссылки подтверждающие что-то искать лень...
8 дек 11, 21:45    [11732826]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
Acce_Ekb
Member

Откуда: Екатеринбург
Сообщений: 87
beg_inner
а если делать как у меня, то, как выше ответили, replicate мне отдаст varchar.
при присвоении varchаr-а varchar(max)-у, сервер должен преобразовывать или нет?
вернее так, какой из серверов ведет себя стандартно, который преобразует (вроде логично преобразовывать, я же явно указала, какого типа переменная) или который отдает упорно просто varchar? и что влияет на поведение сервера, какая настройка?


Перед присваиванием в переменную сначала вычисляется выражение в правой части. При вычислении сервер использует только типы операндов выражения (не смотрит на тип переменной, в которую мы хотим _потом_ записать).

Поэтому для
@s = replicate('a', 5000) + replicate('b', 5000)

выражение replicate('a', 5000) + replicate('b', 5000) после вычисления будет типа varchar (т.е. склеенная строка урежется).

И для
declare @f float
set @f = 1 + 1

действительно сначала результат вычисления урежется до целого типа (tinyint), а уже потом после присваивания в переменную @f будет преобразовано к вещественному типу.

Известные грабли с делением:
declare @f float
set @f = 1/2
select @f
 


вернет 0, а не 0.5.

Никакая настройка не влияет, исправить никак нельзя.
Нужно это помнить, и если где-то грозит потенциальное обрезание, то включать в выражение хотя бы один операнд более "широкого" типа или явно приводить типы.
9 дек 11, 07:46    [11733833]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
tunknown
Member

Откуда:
Сообщений: 777
Ошибка в том, что в BOL(моей версии) в статье Data Type Precedence не указан порядок следование типов varchar(max) и varchar(n). Вывод- наличие в выражении REPLICATE или SPACE с константами или фиксированными типами опасен, если требуется общий результат varchar(max). "@c varchar(1)"- опасная особенность "@c varchar(max)"- безопасно.

set	nocount	on
declare	@s	varchar(max)
--	,@c	varchar(1)
	,@c	varchar(max)

set	@c=	'-'
set	@s='select top 1 * from sysobjects'+REPLICATE (@c,796)+'
select top 1 * from sysobjects'
select datalength(@s)

set	@s='select top 1 * from sysobjects'+REPLICATE (@c,7960)+'
select top 1 * from sysobjects'
select datalength(@s)

set	@s='select top 1 * from sysobjects'+REPLICATE (@c,79600)+'
select top 1 * from sysobjects'
select datalength(@s)
2 мар 12, 12:04    [12182261]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
invm
Member

Откуда: Москва
Сообщений: 9836
tunknown,

REPLICATE (Transact-SQL)
Примечание
Если аргумент string_expression не принадлежит к типу varchar(max) или nvarchar(max), функция REPLICATE усекает возвращаемое значение до 8000 байт. Для возврата значений, превышающих 8 000 байт, аргумент string_expression должен быть явно приведен к соответствующему типу данных с большими значениями.
2 мар 12, 12:23    [12182401]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
шанти
Guest
beg_inner
но тетка, которая мне жаловалась, что ей обрезает, она replicate не использовала совсем, она свои строки слепляла, но явно не преобразовывала. и ей обрезалось.
так что все же дело не в том, что отдает replicate, а в том, что сервер халтурит.


сервер не халтурит, не умеет ибо
смотрите уровень совместимости базы ..
2 мар 12, 12:26    [12182425]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
Geep
Member

Откуда: Москва
Сообщений: 975
что то версий серверов не увидел...
2 мар 12, 12:27    [12182428]     Ответить | Цитировать Сообщить модератору
 Re: nvarchar(max) и 8000 символов  [new]
beg_inner
Guest
уже 5 одинаковых ответoв получено, со времен декабря 2011.
может мне следовало подытожить, чтоб больше этим не озадачивались?

надо было явно привести аргумент к nvarchar(max)

Alexandr Kr.
соответственно если сделать так
set @s = replicate(cast('a' as varchar(max)), 5000) + replicate('b', 5000)
то все будет как ожидаалось


Knyazev Alexey
неявное преобразование!? ;)
declare @s varchar(max)
set @s = cast( replicate('a', 5000) as varchar(max) ) + cast( replicate('b', 5000) as varchar(max) )
select len(@s), datalength(@s)


locky
читайте бол, там всё написано
select datalength(replicate(cast('8' as varchar(max)),163840))
--------------------
163840


iap
Мне мягко указали на явное преобразование аргумента REPLICATE


Acce_Ekb
Перед присваиванием в переменную сначала вычисляется выражение в правой части. При вычислении сервер использует только типы операндов выражения (не смотрит на тип переменной, в которую мы хотим _потом_ записать).
2 мар 12, 13:27    [12182964]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить