Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
Столкнулся с проблемой, как получить случайное число в селекте, желательно чтоб не наворачивать зверскую формулу. Причем чтоб каждый раз был свой набор чисел, чтоб не привязываться к значениям каих-либо полей в таблице. Можно получить уникальны идентификатор NEWID, но тогда строку с шестнадцатеричным числом надо перевести в число. Как его можно перевести? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2002, 09:18 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
A rand() - чем не подходит? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2002, 09:29 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
2Dmitry А Вы попробуйте: select rand() from sysobjects ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2002, 10:01 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
Ну если Вы хотите использовать именно в запросе и чтоб для каждой его строки было свое значение, то можно так select convert (bigint,convert(varbinary,'0x'+convert(varchar(36),(newid())))) from sysobjects Если лениво каждый раз такую штуку писать, а использовать надо часто, то просто создайте UDF, которое будет преобразовывать newid() в число и вызывать ее соответственно потом как Select dbo.myrnd(newid()) from sysobjects ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2002, 12:52 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
>Dmitry Это то что нужно, спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2002, 13:38 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
Хм... Щас вот еще посмотрел, и пришел к выводу что это не совсем правильно. Т.е. для Вас может сгодиться и в таком виде, но преобразование некорректно (т.е. если получаемое число не является записью этого newid() в десятиричной системе). Поэтому лучше самому указать на ошибку чем это сделает кто-то другой Во-первых, собственно, Bigint имеет диапазон -2^63 - 2^63-1 , а у uniqueidentifier (если без палочек) - 0 - 256^16=2^128-1 Поэтому, стремиться перевести его корректно в bigint не стоит Это также означает, что хоть uniqueidentifier обеспечивает глобальную уникальность - кусок его (например полученный через Right) (который можно перевести в bigint) не будет. (Опять же просто для получения случайного числа этого не требуется, вот если б было надо обязательно уникальное случ. число...) Во вторых, собственно некорректен перевод строки, представляющей шестнадцатиричную запись в число (в десятичной форме через перевод в varbinary). Я сделал это потому как напрямую нельзя сделать select convert(bigint,'0xA'), хотя можно select convert(bigint,0xA) Но и перевод через varbinary - неправилен, ибо select convert(varbinary(1),'A') даст 0x61, т.е. ASCII код символа 'А', а не число 10 (шеснадцатирич. -> десят. перевод). И т.д. Поэтому, для получения случ. числа, наверное можно использовать этот метод, но для преобразвания строки, представляющей шестнадцатиричную запись числа в десятичную - нельзя. Может я торможу и не соображу как это сделать просто... Может кто-то подскажет. Но можно решить и в лоб, например так ("корректный" перевод части uniqueidentifier-а в bigint): CREATE FUNCTION dbo.myrand(@uid uniqueidentifier) RETURNS bigint AS BEGIN declare @a varchar(36), @b bigint, @i int, @c tinyint set @a=convert(varchar(36),@uid) set @a= right(@a,12) set @b=0 Set @i=11 while @i>=0 begin if substring(@a,@i,1)>='A' set @c=ascii(substring(@a,@i,1)) else set @c=convert(tinyint,substring(@a,@i,1)) set @b=@b+@c*power(convert(bigint,16),@i) set @i=@i-1 end return @b END ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2002, 14:19 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
Эээх, не мой сегодня день... CREATE FUNCTION dbo.myrand(@uid uniqueidentifier) RETURNS bigint AS BEGIN declare @a varchar(36), @b bigint, @i int, @c tinyint set @a=convert(varchar(36),@uid) set @a= right(@a,12) set @b=0 Set @i=1 while @i<=12 begin if substring(@a,@i,1)>='A' set @c=ascii(substring(@a,@i,1))-55 else set @c=convert(tinyint,substring(@a,@i,1)) set @b=@b+@c*power(convert(bigint,16),12-@i) set @i=@i+1 end return @b END ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2002, 14:40 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
Пожалуйста, не извращайтесь с newid(). Смысл случайного числа - не в неповторяемости значений, а в случайном (может, равномерном?) разбросе значений в некотором диапазоне, чего newid() не обеспечит. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2002, 14:44 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
Я нашел 2 способа получить случайное число, rand() и newid(). Но т.к. использовать его надо внутри запроса, rand не очень подходит. По умолчанию он считает случайное число относительно даты, поэтому в запросе оно всегда получится одинаковое. Поэтому нужно придумать какой-нибудь аргумент для rand. Можно взять какое-нибудь поле для этого, но тогда каждый раз будет один и тот же набор случайных чисел, а для меня это не годится. Собственно говоря надо было из большой базы вопросов отобрать несколько по определенному условию и полученные по одному выдавать клиенту в случайной последовательности. Повторение вопросов допускается. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.03.2002, 08:43 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
rand не очень подходит. По умолчанию он считает случайное число относительно даты, поэтому в запросе оно всегда получится одинаковое Можно и разное получить SELECT id *rand(), (id)*RAND((DATEPART(mm, GETDATE()) * 100000)+ (DATEPART(ss, GETDATE()) * 1000 )+ DATEPART(ms, GETDATE())) from sysobjects По идеи если во 2-3 столбце отбросить целую часть, то можно получить какое-никакое случайное распределение. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.03.2002, 10:21 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
2 Glory: Из самого первого сообщения, т.е. постановки задачи: "чтоб не привязываться к значениям каих-либо полей в таблице." А у Вас все завязано на id... Множитель же на который умножается id - будет одинаковый для всех строк. Т.е. чем больше id, тем больше "случайное число" Отбросить целую часть - идея ничего, но все равно получается фикция: Пусть есть 2 строки со значениями id отличающимися в 2 раза (например 1 и 2) Тогда после перемножения получим, что "случайные" числа отличаются в 2 раза. После отбрасывания целой части будет всего две возможности: 1) в случае, если дробная часть произведения была <0.5 . В этом случае после отбрасывания целой части получим что "случайные" числа для этих строк опять же отличаются в 2 раза. например, cч1=1.38*1-floor(1.38*1)=0.38 сч2=1.38*2-floor(1.38*2)=0.78 сч2=сч1*2 2) в случае, если дробная часть произведения была >0.5 . В этом случае после отбрасывания целой части получим что "случайные" числа для этих строк соотносятся по формуле cч1=(сч2+1)/2. например, cч1=1.56*1-floor(1.56*1)=0.56 сч2=1.56*2-floor(1.56*2)=0.12 сч1=(сч1+1)/2 Для других id отличающихся в 2 раза, но не 1 и 2 - та же ситуация. только немного другое условие - не др. часть произведения> (или <0.5, а др. часть от (произведение*id1/2) > (или < 0.5, где id1 - меньший из id Для id, отличающихся не в 2, а n раз - будет просто больше возможностей, но все равно останется кусочно-заданная зависимость. Т.е. я хочу сказать что все равно получается слишком боьшая корреляция... А для случайных чисел это недопустимо Проблема то в том, что rand, getdate и т.п. вычисляются в момент начала выполнения запроса и будут применены ко всем кортежам. Согласен, что newid() не предназначен для таких целей, но зато он вычисляется для каждого кортежа отдельно, поэтому может все таки стоит его применить для данной задачи. 2 alexeyvg: ОПять же повторюсь, что согласен, что newid() для этого не предназначен, но предложите чего-нибудь лучше. Что касается уникальности получаемого "случайного" числа, то оно тут и не обеспечивается, потому что как я писал выше, придется использовать лишь часть от newid(), а уникальность этой части не гарантируется. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.03.2002, 12:31 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
А если сделать так: \nSELECT id *rand(), (id)*RAND((DATEPART(mm, GETDATE()) * 100000)+ (DATEPART(ss, GETDATE()) * 1000 )+ DATEPART(ms, GETDATE())), RAND((DATEPART(mm, GETDATE()) * 100000)+ (DATEPART(ss, GETDATE()) * 1000 )+ DATEPART(ms, GETDATE())) from sysobjects то станет ясно, что во всех возвращаемых строках "RAND((DATEPART(mm..." принимает одно и то же значение, домножаемое на id, так что между первым и вторым столбцами различия, в общем-то, нет Так что курсор, господа, курсор ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.03.2002, 12:58 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
Полностью согласен Проблема не в том, чтобы сгенерировать правильно случайное число (способы для это известны), а именно в том как SQL вычисляет значения функций, не привязанных к полю запроса. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.03.2002, 13:11 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
2Dmitry Предложение простое - получать список уникальных значений из rand() в цикле. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.03.2002, 13:16 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
Мы оставили без внимание простое решение, вернее модификацию уже предложенного. select rand(convert (int,convert(varbinary,'0x'+convert(varchar(36),(newid()))))) from sysobjects Или в этом варианте тоже есть недостатки? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.03.2002, 15:12 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
Или в этом варианте тоже есть недостатки? В одной из прошлых дискуссий на тему newid() кажется SergSper говорил, что у него наблюдался эффект последовательной генерации значений через определенный промежуток. Мне лично на 2-х моих серверах такого эффекта добиться не удалось, поэтому как говорится "100% гарантию вам может дать только страховой полис" ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.03.2002, 15:23 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
2 Alexeyvg: Теперь уже и Вы заговариваетесь - случайных, а не уникальных А вообще - наверное для того, чтобы иметь тот самый страховой полис, о котором говорил Glory, придется таки пойти на такую жертву (курсор), хотя конечно же, хотелось чего-нить покрасивше, одним взмахом волшебной палочки ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.03.2002, 15:53 |
|
||
|
Случайное число
|
|||
|---|---|---|---|
|
#18+
1. Довольно часто пользуюсь следующим алгоритмом для заполнения БД большим количеством тестовых значений rand(id) * rand(datepart(ms,getdate())) * 100000000 - floor(rand(id) * rand(datepart(ms,getdate())) * 100000000) Для тестирования распределения случайной величины можно воспользоваться скриптиком create table t_test (id int identity, i int) go set nocount on declare @i int set @i = 0 while @i < 100000 begin set @i = @i + 1 insert into t_test (i) select @i from sysobjects end go select ceiling(rand_value * 10), count(ceiling(rand_value * 10)) from ( select rand(id) * rand(datepart(ms,getdate())) * 100000000 - floor(rand(id) * rand(datepart(ms,getdate())) * 100000000) rand_value from t_test ) a group by ceiling(rand_value * 10) order by ceiling(rand_value * 10) go drop table t_test Полученная выборка при достаточно большом объеме записей говорит о равномерном распределении ----------------------------------------------------- ----------- 1.0 410003 2.0 409997 3.0 409999 4.0 410002 5.0 409998 6.0 409999 7.0 410006 8.0 409999 9.0 410004 10.0 409993 Underking говорил, что все это нужно только для того, чтобы выборку "...выдавать клиенту в случайной последовательности" 2. Для случайной выборки в случайном порядке можно воспользоваться следующим declare @_htmt nvarchar(255), @_max_rows int set @_max_rows = 10 set @_htmt = N'select top ' + ltrim(str(ceiling(rand() * @_max_rows)))+ ' a.id from sysobjects a order by newid()' exec (@_htmt) 3. Если необходим просто случайный порядок в выборке, то можно так попробовать select a.id from sysobjects a order by newid() -- если newid() не последовательно генерирует значения или select a.id from sysobjects a order by rand(id) * rand(datepart(ms,getdate())) * 100000000 - floor(rand(id) * rand(datepart(ms,getdate())) * 100000000) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.03.2002, 06:43 |
|
||
|
|

start [/forum/topic.php?desktop=1&fid=46&tid=1823515]: |
0ms |
get settings: |
9ms |
get forum list: |
14ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
22ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
53ms |
get tp. blocked users: |
1ms |
| others: | 245ms |
| total: | 362ms |

| 0 / 0 |
