Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Случайное число / 18 сообщений из 18, страница 1 из 1
14.03.2002, 09:18
    #32025190
Underking
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
Столкнулся с проблемой, как получить случайное число в селекте, желательно чтоб не наворачивать зверскую формулу. Причем чтоб каждый раз был свой набор чисел, чтоб не привязываться к значениям каих-либо полей в таблице.

Можно получить уникальны идентификатор NEWID, но тогда строку с шестнадцатеричным числом надо перевести в число. Как его можно перевести?
...
Рейтинг: 0 / 0
14.03.2002, 09:29
    #32025194
dmitry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
A rand() - чем не подходит?
...
Рейтинг: 0 / 0
14.03.2002, 10:01
    #32025203
alexeyvg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
2Dmitry
А Вы попробуйте:

select rand()
from sysobjects
...
Рейтинг: 0 / 0
14.03.2002, 12:52
    #32025243
dmitry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
Ну если Вы хотите использовать именно в запросе и чтоб для каждой его строки было свое значение, то можно так
select convert (bigint,convert(varbinary,'0x'+convert(varchar(36),(newid()))))
from sysobjects

Если лениво каждый раз такую штуку писать, а использовать надо часто, то просто создайте UDF, которое будет преобразовывать newid() в число и вызывать ее соответственно потом как Select dbo.myrnd(newid()) from sysobjects
...
Рейтинг: 0 / 0
14.03.2002, 13:38
    #32025252
Underking
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
>Dmitry
Это то что нужно, спасибо.
...
Рейтинг: 0 / 0
14.03.2002, 14:19
    #32025257
dmitry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
Хм... Щас вот еще посмотрел, и пришел к выводу что это не совсем правильно. Т.е. для Вас может сгодиться и в таком виде, но преобразование некорректно (т.е. если получаемое число не является записью этого 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
...
Рейтинг: 0 / 0
14.03.2002, 14:40
    #32025264
dmitry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
Эээх, не мой сегодня день...


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
...
Рейтинг: 0 / 0
14.03.2002, 14:44
    #32025266
alexeyvg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
Пожалуйста, не извращайтесь с newid().
Смысл случайного числа - не в неповторяемости значений, а в случайном (может, равномерном?) разбросе значений в некотором диапазоне, чего newid() не обеспечит.
...
Рейтинг: 0 / 0
15.03.2002, 08:43
    #32025349
Underking
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
Я нашел 2 способа получить случайное число, rand() и newid(). Но т.к. использовать его надо внутри запроса, rand не очень подходит. По умолчанию он считает случайное число относительно даты, поэтому в запросе оно всегда получится одинаковое. Поэтому нужно придумать какой-нибудь аргумент для rand. Можно взять какое-нибудь поле для этого, но тогда каждый раз будет один и тот же набор случайных чисел, а для меня это не годится.

Собственно говоря надо было из большой базы вопросов отобрать несколько по определенному условию и полученные по одному выдавать клиенту в случайной последовательности. Повторение вопросов допускается.
...
Рейтинг: 0 / 0
15.03.2002, 10:21
    #32025373
Glory
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
rand не очень подходит. По умолчанию он считает случайное число относительно даты, поэтому в запросе оно всегда получится одинаковое
Можно и разное получить

SELECT id *rand(), (id)*RAND((DATEPART(mm, GETDATE()) * 100000)+ (DATEPART(ss, GETDATE()) * 1000 )+ DATEPART(ms, GETDATE()))
from sysobjects

По идеи если во 2-3 столбце отбросить целую часть, то можно получить какое-никакое случайное распределение.
...
Рейтинг: 0 / 0
15.03.2002, 12:31
    #32025394
dmitry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
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 - та же ситуация. только немного другое условие - не др. часть произведения> (или &lt0.5, а др. часть от (произведение*id1/2) > (или &lt 0.5, где id1 - меньший из id
Для id, отличающихся не в 2, а n раз - будет просто больше возможностей, но все равно останется кусочно-заданная зависимость.

Т.е. я хочу сказать что все равно получается слишком боьшая корреляция... А для случайных чисел это недопустимо

Проблема то в том, что rand, getdate и т.п. вычисляются в момент начала выполнения запроса и будут применены ко всем кортежам. Согласен, что newid() не предназначен для таких целей, но зато он вычисляется для каждого кортежа отдельно, поэтому может все таки стоит его применить для данной задачи.


2 alexeyvg: ОПять же повторюсь, что согласен, что newid() для этого не предназначен, но предложите чего-нибудь лучше.
Что касается уникальности получаемого "случайного" числа, то оно тут и не обеспечивается, потому что как я писал выше, придется использовать лишь часть от newid(), а уникальность этой части не гарантируется.
...
Рейтинг: 0 / 0
15.03.2002, 12:58
    #32025400
Александр Степанов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
А если сделать так:
\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, так что между первым и вторым столбцами различия, в общем-то, нет


Так что курсор, господа, курсор
...
Рейтинг: 0 / 0
15.03.2002, 13:11
    #32025401
Glory
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
Полностью согласен
Проблема не в том, чтобы сгенерировать правильно случайное число (способы для это известны), а именно в том как SQL вычисляет значения функций, не привязанных к полю запроса.
...
Рейтинг: 0 / 0
15.03.2002, 13:16
    #32025403
alexeyvg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
2Dmitry
Предложение простое - получать список уникальных значений из rand() в цикле.
...
Рейтинг: 0 / 0
15.03.2002, 15:12
    #32025432
Underking
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
Мы оставили без внимание простое решение, вернее модификацию уже предложенного.
select rand(convert (int,convert(varbinary,'0x'+convert(varchar(36),(newid())))))
from sysobjects
Или в этом варианте тоже есть недостатки?
...
Рейтинг: 0 / 0
15.03.2002, 15:23
    #32025434
Glory
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
Или в этом варианте тоже есть недостатки?

В одной из прошлых дискуссий на тему newid() кажется SergSper говорил, что у него наблюдался эффект последовательной генерации значений через определенный промежуток. Мне лично на 2-х моих серверах такого эффекта добиться не удалось, поэтому как говорится "100% гарантию вам может дать только страховой полис"
...
Рейтинг: 0 / 0
17.03.2002, 15:53
    #32025477
dmitry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
2 Alexeyvg: Теперь уже и Вы заговариваетесь - случайных, а не уникальных

А вообще - наверное для того, чтобы иметь тот самый страховой полис, о котором говорил Glory, придется таки пойти на такую жертву (курсор), хотя конечно же, хотелось чего-нить покрасивше, одним взмахом волшебной палочки
...
Рейтинг: 0 / 0
18.03.2002, 06:43
    #32025492
Mart
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Случайное число
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)
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Случайное число / 18 сообщений из 18, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]