2009-09-23 4 views
7

Ich versuche, Werte zufällig aus einer Liste vordefinierter Werte in eine Tabelle zum Testen einzufügen. Ich habe versucht, die Lösung auf dieser Frage Stackoverflow gefunden werden:Wie kann ich Zufallswerte in eine SQL Server-Tabelle einfügen?

stackoverflow.com/.../update-sql-table-with-random-value-from-other-table

Als ich ich das versucht, alle meine „random“ Werte, die genau das gleiche für alle 3000 Datensätze eingefügt sind.

Wenn ich den Teil der Abfrage, die tatsächlich die zufällige Zeile auswählt, ausführen, wählt es jedes Mal einen zufälligen Datensatz aus, wenn ich es manuell ausführe, also weiß ich, dass die Abfrage funktioniert. Meine beste Vermutungen darüber, was geschieht, sind:

  • SQL Server die SELECT irgendwie optimiert, ohne dass sich die Unterabfrage mehr ausgewertet werden als einmal
  • der Zufallswert Samen auf jeden Datensatz die gleiche ist die Abfrage-Updates

Ich bin fest, was meine Möglichkeiten sind. Mache ich etwas falsch, oder sollte ich das anders machen?

Dies ist der Code Ich verwende:

DECLARE @randomStuff TABLE ([id] INT, [val] VARCHAR(100)) 

INSERT INTO @randomStuff ([id], [val]) 
VALUES (1, 'Test Value 1') 
INSERT INTO @randomStuff ([id], [val]) 
VALUES (2, 'Test Value 2') 
INSERT INTO @randomStuff ([id], [val]) 
VALUES (3, 'Test Value 3') 
INSERT INTO @randomStuff ([id], [val]) 
VALUES (4, 'Test Value 4') 
INSERT INTO @randomStuff ([id], [val]) 
VALUES (5, 'Test Value 5') 
INSERT INTO @randomStuff ([id], [val]) 
VALUES (6, null) 
INSERT INTO @randomStuff ([id], [val]) 
VALUES (7, null) 
INSERT INTO @randomStuff ([id], [val]) 
VALUES (8, null) 
INSERT INTO @randomStuff ([id], [val]) 
VALUES (9, null) 
INSERT INTO @randomStuff ([id], [val]) 
VALUES (10, null) 

UPDATE MyTable 
SET MyColumn = (SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID()) 
+0

Diese Frage/Antwort kann nützlich sein: http://stackoverflow.com/a/9039661/47226 –

Antwort

14

Wenn die Abfrage-Engine das sieht ...

(SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID()) 

... es ist alles mögen „, ooooh, eine cachable skalare Unterabfrage, I Ich werde das zwischenspeichern! "

Sie müssen die Abfrage-Engine dazu bringen, zu denken, dass sie nicht cachbar ist. Jfars answer war in der Nähe, aber die Abfrage-Engine war schlau genug, um die Tautalogie von MyTable.MyColumn = MyTable.MyColumn zu sehen, aber es ist nicht schlau genug, um dies zu durchschauen.

UPDATE MyTable 
    SET MyColumn = (SELECT TOP 1 val 
        FROM @randomStuff r 
          INNER JOIN MyTable _MT 
            ON M.Id = _MT.Id 
        ORDER BY NEWID()) 
FROM MyTable M 

in der äußeren Tabelle (MT) in die Unterabfrage Indem nehmen die Abfrage-Engine Unterabfrage benötigt, neu bewertet werden. Alles wird wirklich funktionieren, aber ich ging mit dem (angenommenen) Primärschlüssel von MyTable.Id, da es indexiert würde und sehr wenig Overhead hinzufügen würde.

Ein Cursor würde wahrscheinlich genauso schnell sein, ist aber sicherlich nicht so lustig.

+0

OK, ich kann mich nicht erinnern, ob Sie den INNER JOIN so in SQL Server 2000 machen können, aber es gibt einen Weg, den ich die ganze Zeit vor 2005 nutzte. Das war zu viele Jahre für mich, um mich daran zu erinnern obwohl. Aber das sollte 2005 und später gut funktionieren. –

+1

Das hat hervorragend funktioniert. Vielen Dank! –

+2

+1 das ist fantastisch, es gibt einen kleinen Tippfehler, 'ON MT.Id = _MT.Id' sollte' ON M.Id = _MT.Id' sein – Rippo

0

Ich habe keine Zeit, dieses Recht jetzt zu überprüfen, aber mein Bauchgefühl sagt mir, dass, wenn Sie sind eine Funktion auf dem Server erstellen zu bekommen der zufällige Wert, den es nicht optimieren würde.

dann würden Sie

UPDATE MyTable 
Set MyColumn = dbo.RANDOM_VALUE() 
0

haben Es gibt keine Optimierung geht hier vor.

Wenn Sie eine Unterabfrage verwenden, die einen einzelnen Wert auswählt, gibt es nichts zu optimieren.

Sie können auch versuchen, eine Spalte aus der Tabelle Ihre Aktualisierung in der Auswahl und sehen, ob das etwas ändert. Das kann eine Auswertung für jede Zeile in MyTable triggern

UPDATE MyTable 
SET MyColumn = (SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID() 
    WHERE MyTable.MyColumn = MyTable.MyColumn) 
+1

Ich habe es gerade versucht. Hatte kein Glück, die Ergebnisse zu ändern. –

2

Verwendung eine Quer verbinden, um zufällige Daten zu erzeugen

+0

Hast du ein Beispiel, das ich benutzen könnte? Ich bin nicht mit der Idee von Cross-Joins vertraut. –

0

I kam eine Lösung, die ein wenig wie ein Hack und sehr ineffizient (10 ~ Sekunden Update 3000 Datensätze). Da dies zur Generierung von Testdaten verwendet wird, muss ich mich nicht um die Geschwindigkeit kümmern.

In dieser Lösung iteriere ich über jede Zeile in der Tabelle und aktualisiere die Werte Zeile für Zeile. Es scheint zu funktionieren:

1

Ich hatte ein Spiel mit diesem und fand eine ziemlich hacky Weise, es mit der Verwendung einer Zwischentabellenvariablen zu tun.

Sobald @randomStuff eingerichtet ist, wir tun, um diese (Anmerkung in meinem Fall @MyTable ist eine Tabelle, variabel, entsprechend anpassen für Ihre normale Tabelle):

DECLARE @randomMappings TABLE (id INT, val VARCHAR(100), sorter UNIQUEIDENTIFIER) 

INSERT INTO @randomMappings 
SELECT M.id, val, NEWID() AS sort 
FROM @MyTable AS M 
CROSS JOIN @randomstuff 

so an dieser Stelle haben wir ein Zwischentabelle mit jeder Kombination aus (Mytable-ID, Zufallswert) und einem zufälligen Sortierwert für jede Zeile, die für diese Kombination spezifisch ist.Dann

DELETE others FROM @randomMappings AS others 
INNER JOIN @randomMappings AS lower 
ON (lower.id = others.id) AND (lower.sorter < others.sorter) 

Dies ist ein alter Trick, der alle Zeilen für einen bestimmten MyTable.id löscht mit Ausnahme des einen mit dem unteren Sortierwert - die Tabelle mit sich selbst verbinden, in dem der Wert kleiner ist, und löschen Sie alle, wenn diese ein Join ist gelungen. Dies hinterlässt nur den niedrigsten Wert. Also für jeden MyTable.id, wir haben nur eine (zufällige) Wert links .. Dann haben wir es einfach anschließen zurück in die Tabelle:

UPDATE @MyTable 
SET MyColumn = random.val 
FROM @MyTable m, @randomMappings AS random 
WHERE (random.id = m.id) 

Und Sie sind fertig!

Ich sagte es Hacky war ...

Verwandte Themen