شبه عشوائية متكرر ترتيب في SQL Server (لا NEWID () وليس RAND ())

StackOverflow https://stackoverflow.com/questions/458175

سؤال

وأود أن فرز عشوائيا نتيجة لذلك بطريقة تكرار لأغراض مثل الترحيل. لهذا NEWID () هو عشوائي جدا في أن نفس النتائج لا يمكن إعادة الحصول عليها. سيكون النظام من قبل راند (البذور) تكون مثالية كما هو الحال مع نفس البذور من شأنه أن يؤدي نفس مجموعة عشوائية. وللأسف، فإن راند () يعيد الدولة مع كل صف، لا أحد يملك الحل؟

declare @seed as int;
set @seed = 1000;

create table temp (
id int,
date datetime)

insert into temp (id, date) values (1,'20090119')
insert into temp (id, date) values (2,'20090118')
insert into temp (id, date) values (3,'20090117')
insert into temp (id, date) values (4,'20090116')
insert into temp (id, date) values (5,'20090115')
insert into temp (id, date) values (6,'20090114')

-- re-seeds for every item
select *, RAND(), RAND(id+@seed) as r from temp order by r
--1 2009-01-19 00:00:00.000 0.277720118060575   0.732224964471124
--2 2009-01-18 00:00:00.000 0.277720118060575   0.732243597442382
--3 2009-01-17 00:00:00.000 0.277720118060575   0.73226223041364
--4 2009-01-16 00:00:00.000 0.277720118060575   0.732280863384898
--5 2009-01-15 00:00:00.000 0.277720118060575   0.732299496356156
--6 2009-01-14 00:00:00.000 0.277720118060575   0.732318129327415
-- Note how the last column is +=~0.00002

drop table temp

-- interestingly this works:
select RAND(@seed), RAND()
--0.732206331499865 0.306382810665955

ملحوظة، حاولت راند (ID)، ولكن أن يتحول فقط إلى أن تكون مرتبة. يبدو راند (ن) <راند (ن + 1)

هل كانت مفيدة؟

المحلول

وبناء الخروج من gkrogers اقتراح التجزئة هذا يعمل كبيرة. أية أفكار حول الأداء؟

declare @seed as int;
set @seed = 10;

create table temp (
id int,
date datetime)

insert into temp (id, date) values (1,'20090119')
insert into temp (id, date) values (2,'20090118')
insert into temp (id, date) values (3,'20090117')
insert into temp (id, date) values (4,'20090116')
insert into temp (id, date) values (5,'20090115')
insert into temp (id, date) values (6,'20090114')

-- re-seeds for every item
select *, HASHBYTES('md5',cast(id+@seed as varchar)) r
from temp order by r
--1 2009-01-19 00:00:00.000 0x6512BD43D9CAA6E02C990B0A82652DCA
--5 2009-01-15 00:00:00.000 0x9BF31C7FF062936A96D3C8BD1F8F2FF3
--4 2009-01-16 00:00:00.000 0xAAB3238922BCC25A6F606EB525FFDC56
--2 2009-01-18 00:00:00.000 0xC20AD4D76FE97759AA27A0C99BFF6710
--3 2009-01-17 00:00:00.000 0xC51CE410C124A10E0DB5E4B97FC2AF39
--6 2009-01-14 00:00:00.000 0xC74D97B01EAE257E44AA9D5BADE97BAF

drop table temp

وتحرير: لاحظ، وإعلانseed كما انها تستخدم في الاستعلام يمكن استبدالها مع المعلمة أو مع كثافة ثابتة إذا تم استخدام SQL الحيوية. (إعلانint بطريقة TSQL ليس ضروريا)

نصائح أخرى

ويمكنك استخدام قيمة من كل صف لإعادة تقييم وظيفة راند:

Select *, Rand(@seed + id) as r from temp order by r

وإضافة ID يضمن أن الراند هو reseeded لكل صف. ولكن لقيمة البذور ستحصل دائما العودة نفس تسلسل الصفوف (شريطة أن لا يتغير الجدول)

وإنشاء تجزئة يمكن أن يكون أكثر من ذلك بكثير تستغرق وقتا طويلا من إنشاء رقم عشوائي المصنف.

لحصول على مزيد من التباين في ourput من RAND ([البذور]) تحتاج إلى جعل [البذور] تختلف بشكل كبير جدا. هذا ربما ما ...

SELECT
    *,
    RAND(id * 9999)    AS [r]
FROM
   temp
ORDER BY
   r

وعن طريق ثابت يضمن تكرار الذي طلب. ولكن كن حذرا من نتيجة (معرف * 9999) مما تسبب في فيضان إذا كنت تتوقع الجدول الخاص بك للحصول على كبيرة بما يكفي ...

SELECT *, checksum(id) AS r FROM table ORDER BY r

وهذا النوع من الأعمال. على الرغم من أن الإخراج من اختباري () لا تبدو كل ذلك عشوائي لي. و MSDN الوثائق ما يلي:

<اقتباس فقرة>   

[...]، ونحن لا نوصي باستخدام تدقيق لاكتشاف ما إذا كان القيم قد تغيرت، ما لم يمكن أن يتسامح مع التطبيق الخاص بك في بعض الأحيان في عداد المفقودين التغيير. النظر في استخدام HashBytes بدلا من ذلك. عندما يتم تحديد خوارزمية البعثرة MD5، واحتمال عودته HashBytes نفس النتيجة لاثنين من المدخلات المختلفة هو أقل بكثير من تدقيق.

ولكن قد يكون ذلك بشكل أسرع.

وبعد القيام ببعض هذه القراءة هي الطريقة المقبولة.

Select Rand(@seed) -- now rand is seeded

Select *, 0 * id + Rand() as r from temp order by r

وجود معرف في التعبير يسبب أن يتم إعادة تقييم كل صف. ولكن ضرب من قبل 0 يضمن أن هو لا لا يؤثر على نتائج راند.

ما هي طريقة رهيبة للقيام بهذه الأمور!

لقد عملت هذا جيد بالنسبة لي في الماضي، وأنه يمكن تطبيقها على أي جدول (الترباس فقط على جملة ORDER BY):

SELECT *
FROM MY_TABLE
ORDER BY  
  (SELECT ABS(CAST(NEWID() AS BINARY(6)) % 1000) + 1);
create table temp (
id int,
date datetime)

insert into temp (id, date) values (1,'20090119')
insert into temp (id, date) values (2,'20090118')
insert into temp (id, date) values (3,'20090117')
insert into temp (id, date) values (4,'20090116')
insert into temp (id, date) values (5,'20090115')
insert into temp (id, date) values (6,'20090114')

-- re-seeds for every item
select *, NEWID() r
from temp order by r

drop table temp
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top