it-swarm.com.de

Wie generiere ich eine Zufallszahl für jede Zeile in einem TSQL Select?

Ich benötige für jede Zeile in meiner Tabelle eine andere Zufallszahl. Der folgende scheinbar offensichtliche Code verwendet für jede Zeile denselben Zufallswert.

SELECT table_name, Rand() magic_number 
FROM information_schema.tables 

Ich würde gerne ein INT oder ein FLOAT daraus machen. Der Rest der Geschichte ist, dass ich diese Zufallszahl verwenden werde, um einen zufälligen Datumsversatz von einem bekannten Datum zu erstellen, z. 1-14 Tage von einem Startdatum versetzt.

Dies ist für Microsoft SQL Server 2000.

302
MatthewMartin

Schauen Sie sich SQL Server - Set based random numbers an, das eine sehr ausführliche Erklärung enthält.

Zusammenfassend generiert der folgende Code eine Zufallszahl zwischen 0 und einschließlich 13 mit einer normalisierten Verteilung:

ABS(CHECKSUM(NewId())) % 14

Um Ihren Bereich zu ändern, ändern Sie einfach die Nummer am Ende des Ausdrucks. Seien Sie besonders vorsichtig, wenn Sie einen Bereich benötigen, der sowohl positive als auch negative Zahlen enthält. Wenn Sie es falsch machen, ist es möglich, die Zahl 0 doppelt zu zählen.

Eine kleine Warnung für die Mathematikfreaks im Raum: Dieser Code enthält eine sehr geringe Abweichung. CHECKSUM() führt zu Zahlen, die über den gesamten Bereich des SQL Int-Datentyps hinweg einheitlich sind, oder zumindest so nahe, wie meine Tests (des Editors) zeigen können. Es wird jedoch eine gewisse Verzerrung geben, wenn CHECKSUM () eine Zahl ganz am oberen Ende dieses Bereichs erzeugt. Jedes Mal, wenn Sie eine Zahl zwischen der maximal möglichen Ganzzahl und dem letzten exakten Vielfachen der Größe Ihres gewünschten Bereichs (in diesem Fall 14) vor dieser maximalen Ganzzahl erhalten, werden diese Ergebnisse dem verbleibenden Teil Ihres Bereichs vorgezogen, aus dem nicht produziert werden kann das letzte Vielfache von 14.

Stellen Sie sich beispielsweise vor, der gesamte Bereich des Int-Typs ist nur 19. 19 ist die größtmögliche Ganzzahl, die Sie aufnehmen können. Wenn CHECKSUM () zu 14-19 führt, entsprechen diese den Ergebnissen 0-5. Diese Zahlen wären gegenüber 6-13 stark bevorzugt, da CHECKSUM () sie mit doppelter Wahrscheinlichkeit erzeugt. Es ist einfacher, dies visuell zu demonstrieren. Nachfolgend finden Sie die gesamte mögliche Ergebnismenge für unseren imaginären ganzzahligen Bereich:

 Checksum Integer: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
 Range Result: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 1 2 3 4 5 

Sie sehen hier, dass es mehr Chancen gibt, einige Zahlen als andere zu produzieren: Voreingenommenheit. Glücklicherweise ist der tatsächliche Bereich des Int-Typs viel größer, so dass die Verzerrung in den meisten Fällen nahezu nicht nachweisbar ist. Es ist jedoch wichtig zu wissen, ob Sie dies jemals aus Sicherheitsgründen tun.

476
SQLMenace

Bei mehreren Aufrufen in einem Stapel gibt Rand () dieselbe Nummer zurück.

Ich würde vorschlagen, convert (varbinary, newid()) als Ausgangsargument zu verwenden:

SELECT table_name, 1.0 + floor(14 * Rand(convert(varbinary, newid()))) magic_number 
FROM information_schema.tables

newid() gibt garantiert bei jedem Aufruf einen anderen Wert zurück, auch innerhalb desselben Stapels. Wenn Sie es als Startwert verwenden, wird Rand () jedes Mal aufgefordert, einen anderen Wert anzugeben.

Bearbeitet, um eine zufällige ganze Zahl von 1 bis 14 zu erhalten.

89
Jeremy Smyth
Rand(CHECKSUM(NEWID()))

Das Obige erzeugt eine (Pseudo-) Zufallszahl zwischen 0 und 1, exklusiv. Bei Verwendung in einer Auswahl wird, da sich der Startwert für jede Zeile ändert, eine neue Zufallszahl für jede Zeile generiert (es kann jedoch nicht garantiert werden, dass pro Zeile eine eindeutige Zahl generiert wird).

Beispiel in Kombination mit einer Obergrenze von 10 (ergibt die Zahlen 1 - 10):

CAST(Rand(CHECKSUM(NEWID())) * 10 as INT) + 1

Transact-SQL-Dokumentation:

  1. CAST(): https://docs.Microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql
  2. Rand(): http://msdn.Microsoft.com/en-us/library/ms177610.aspx
  3. CHECKSUM(): http://msdn.Microsoft.com/en-us/library/ms189788.aspx
  4. NEWID(): https://docs.Microsoft.com/en-us/sql/t-sql/functions/newid-transact-sql
66
Aaron Hoffman

Zufallszahlengenerierung zwischen 1000 und 9999 inklusive:

FLOOR(Rand(CHECKSUM(NEWID()))*(9999-1000+1)+1000)

"+1" - um Werte für die obere Grenze einzuschließen (9999 für das vorherige Beispiel)

35
Vova

Beantwortung der alten Frage, aber diese Antwort wurde vorher nicht gegeben, und hoffentlich ist dies nützlich für jemanden, der diese Ergebnisse über eine Suchmaschine findet.

Mit SQL Server 2008 wurde die neue Funktion CRYPT_GEN_RANDOM(8) eingeführt, die CryptoAPI verwendet, um eine kryptografisch starke Zufallszahl zu erstellen, die als VARBINARY(8000) zurückgegeben wird. Hier ist die Dokumentationsseite: https://docs.Microsoft.com/en-us/sql/t-sql/functions/crypt-gen-random-transact-sql

Um eine Zufallszahl zu erhalten, können Sie die Funktion einfach aufrufen und in den erforderlichen Typ umwandeln:

select CAST(CRYPT_GEN_RANDOM(8) AS bigint)

oder um ein float zwischen -1 und +1 zu erhalten, könnten Sie so etwas tun:

select CAST(CRYPT_GEN_RANDOM(8) AS bigint) % 1000000000 / 1000000000.0
19
Andrei Tanas

Die Funktion Rand () generiert die gleiche Zufallszahl, wenn sie in einer Tabellen-SELECT-Abfrage verwendet wird. Gleiches gilt, wenn Sie einen Startwert für die Rand-Funktion verwenden. Eine alternative Möglichkeit, dies zu tun, besteht darin, Folgendes zu verwenden:

SELECT ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) AS [RandomNumber]

Habe die Information von hier , was das Problem sehr gut erklärt.

11
MicSim

Wenn Sie Ihr Saatgut aufbewahren müssen, damit es jedes Mal die "gleichen" Zufallsdaten generiert, können Sie Folgendes tun:

1. Erstellen Sie eine Ansicht, die select Rand () zurückgibt

if object_id('cr_sample_randView') is not null
begin
    drop view cr_sample_randView
end
go

create view cr_sample_randView
as
select Rand() as random_number
go

2. Erstellen Sie eine UDF, die den Wert aus der Ansicht auswählt.

if object_id('cr_sample_fnPerRowRand') is not null
begin
    drop function cr_sample_fnPerRowRand
end
go

create function cr_sample_fnPerRowRand()
returns float
as
begin
    declare @returnValue float
    select @returnValue = random_number from cr_sample_randView
    return @returnValue
end
go

. Setzen Sie vor der Auswahl Ihrer Daten die Rand () - Funktion und verwenden Sie dann die UDF in Ihrer select-Anweisung.

select Rand(200);   -- see the Rand() function
with cte(id) as
(select row_number() over(order by object_id) from sys.all_objects)
select 
    id,
    dbo.cr_sample_fnPerRowRand()
from cte
where id <= 1000    -- limit the results to 1000 random numbers
5
Mitselplik

Haben Sie in jeder Zeile einen ganzzahligen Wert, den Sie als Startwert an die Rand-Funktion übergeben könnten?

Um eine ganze Zahl zwischen 1 und 14 zu erhalten, denke ich, dass dies funktionieren würde:

FLOOR( Rand(<yourseed>) * 14) + 1
5
CoderDennis
select round(Rand(checksum(newid()))*(10)+20,2)

Hier liegt die Zufallszahl zwischen 20 und 30. round gibt maximal zwei Dezimalstellen an.

Wenn Sie negative Zahlen wollen, können Sie es mit tun

select round(Rand(checksum(newid()))*(10)-60,2)

Dann ist der Mindestwert -60 und der Höchstwert -50.

4
Tirthankar

versuchen Sie, einen Startwert in Rand (seedInt) zu verwenden. Rand () wird nur einmal pro Anweisung ausgeführt, daher wird jedes Mal dieselbe Zahl angezeigt.

4
northpole

Wenn Sie nicht benötigen, dass es sich um eine Ganzzahl handelt, sondern um einen beliebigen eindeutigen Bezeichner, können Sie newid() verwenden.

SELECT table_name, newid() magic_number 
FROM information_schema.tables
4
4
David
select ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) as [Randomizer]

hat immer für mich gearbeitet

2
theteague

wählen Sie newid ()

oder möglicherweise dieses select binary_checksum (newid ())

2
Chris Klepeis

Es ist so einfach wie:

DECLARE @rv FLOAT;
SELECT @rv = Rand();

Und dies wird eine Zufallszahl zwischen 0-99 in eine Tabelle setzen:

CREATE TABLE R
(
    Number int
)

DECLARE @rv FLOAT;
SELECT @rv = Rand();

INSERT INTO dbo.R
(Number)
    values((@rv * 100));

SELECT * FROM R
2
Rosjier Hall

Das Problem, das ich manchmal mit der ausgewählten "Antwort" habe, ist, dass die Verteilung nicht immer gleichmäßig ist. Wenn Sie eine sehr gleichmäßige Verteilung von zufällig 1 - 14 auf viele Zeilen benötigen, können Sie so etwas tun (meine Datenbank hat 511 Tabellen, das funktioniert also. Wenn Sie weniger Zeilen als Zufallszahlen haben, funktioniert dies nicht Gut):

SELECT table_name, ntile(14) over(order by newId()) randomNumber 
FROM information_schema.tables

Diese Art von macht das Gegenteil von normalen Zufallslösungen in dem Sinne, dass die Zahlen sequenziert bleiben und die andere Spalte zufällig angeordnet wird.

Denken Sie daran, ich habe 511 Tabellen in meiner Datenbank (was nur b/c relevant ist, die wir aus dem information_schema auswählen). Wenn ich die vorherige Abfrage nehme und sie in eine temporäre Tabelle #X lege und dann diese Abfrage für die resultierenden Daten ausführe:

select randomNumber, count(*) ct from #X
group by randomNumber

Ich erhalte dieses Ergebnis, das mir zeigt, dass meine Zufallszahl SEHR gleichmäßig auf die vielen Zeilen verteilt ist:

enter image description here

2
Trevor
    DROP VIEW IF EXISTS vwGetNewNumber;
    GO
    Create View vwGetNewNumber
    as
    Select CAST(Rand(CHECKSUM(NEWID())) * 62 as INT) + 1 as NextID,
    'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'as alpha_num;

    ---------------CTDE_GENERATE_PUBLIC_KEY -----------------
    DROP FUNCTION IF EXISTS CTDE_GENERATE_PUBLIC_KEY;  
    GO
    create function CTDE_GENERATE_PUBLIC_KEY()
    RETURNS NVARCHAR(32)
    AS 
    BEGIN
        DECLARE @private_key NVARCHAR(32);
        set @private_key = dbo.CTDE_GENERATE_32_BIT_KEY();
        return @private_key;
    END;
    go

---------------CTDE_GENERATE_32_BIT_KEY -----------------
DROP FUNCTION IF EXISTS CTDE_GENERATE_32_BIT_KEY;  
GO
CREATE function CTDE_GENERATE_32_BIT_KEY()
RETURNS NVARCHAR(32)
AS 
BEGIN
    DECLARE @public_key NVARCHAR(32);
    DECLARE @alpha_num NVARCHAR(62);
    DECLARE @start_index INT = 0;
    DECLARE @i INT = 0;
    select top 1 @alpha_num = alpha_num from vwGetNewNumber;
        WHILE @i < 32
        BEGIN
          select top 1 @start_index = NextID from vwGetNewNumber;
          set @public_key = concat (substring(@alpha_num,@start_index,1),@public_key);
          set @i = @i + 1;
        END;
    return @public_key;
END;
    select dbo.CTDE_GENERATE_PUBLIC_KEY() public_key;
1
ichak khoury

Aktualisiere my_table set my_field = CEILING ((Rand (CAST (NEWID () AS varbinary)) * 10))

Nummer zwischen 1 und 10.

0
user3478586