Frage

Ich mag zufällig ein Ergebnis in einer wiederholbaren Art und Weise für Zwecke wie Paging sortieren. Für diese NEWID () ist zu zufällig, dass die gleichen Ergebnisse können nicht wieder erreicht werden. Sortieren nach Rande (Samen) würde mit dem gleichen Samen ideal die gleiche zufällige Ansammlung würde. Leider, der Rand () Zustand setzt mit jeder Zeile hat jemand eine Lösung?

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

Beachten Sie, ich versuchte Rand (ID), aber das stellt sich nur aussortiert werden. Offenbar Rand (n)

War es hilfreich?

Lösung

Gebäude weg von gkrogers Hash-Vorschlag funktioniert dies sehr gut. Irgendwelche Gedanken auf die Leistung?

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

EDIT: Beachten Sie, dass die Deklaration von @seed wie es der Verwendung in der Abfrage ist könnte mit einem Parameter oder mit einem konstanten int wird ersetzen, wenn dynamischer SQL verwendet wird. (Erklärung von @int in einer TSQL Art und Weise ist nicht erforderlich)

Andere Tipps

Sie können einen Wert aus jeder Zeile verwenden, um die Funktion rand neu zu bewerten:

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

die ID hinzugefügt wird sichergestellt, dass der Rand für jede Zeile reseeded wird. Aber für einen Wert von Samen Sie immer die gleiche Folge von Zeilen werden wieder (vorausgesetzt, dass die Tabelle ändert sich nicht)

einen Hash erstellen kann viel mehr Zeit in Anspruch nimmt als eine geimpften Zufallszahl erzeugt wird.

Für weitere Variation der ourput von RAND ([Samen]) erhalten müssen Sie die [Samen] variieren deutlich zu machen. Möglicherweise wie ...

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

eine konstante Verwendung gewährleistet die Nachvollziehbarkeit Sie gefragt. Aber Vorsicht des Ergebnisses (id * 9999) verursacht einen Überlauf, wenn Sie Ihren Tisch erwarten groß genug, um zu bekommen ...

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

Diese Art der Arbeiten. Obwohl die Ausgabe von Prüfsumme () sieht nicht alles, was zufällig zu mir. Die MSDN Dokumentation heißt es:

  

[...], empfehlen wir nicht CHECKSUM verwenden zu erkennen, ob die Werte geändert haben, es sei denn, Ihre Anwendung tolerieren kann eine Änderung gelegentlich fehlt. Betrachten Sie HashBytes stattdessen verwenden. Wenn ein MD5-Hash-Algorithmus festgelegt ist, die Wahrscheinlichkeit des HashBytes das gleiche Ergebnis für zwei verschiedene Eingänge Rückkehr ist viel geringer als die von CHECKSUM.

Aber kann es schneller sein.

Nachdem ich einige der Lektüre dieses ist eine anerkannte Methode zu tun.

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

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

Mit id in der Expression bewirkt, dass es jede Zeile neu bewertet werden. Aber es von 0 multipliziert wird sichergestellt, dass es nicht das Ergebnis von rand beeinflussen tut.

Was für eine schreckliche Art und Weise, Dinge zu tun!

Das ist gut für mich in der Vergangenheit gearbeitet, und es kann (nur Schraube auf der ORDER BY-Klausel) zu einer Tabelle angewandt werden:

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top