2010-08-20 9 views
9

Nach ein wenig Suchen und Lesen der Dokumentation, ist es klar, dass Sie benutzerdefinierte Funktionen in SQL Server schreiben können, die entweder deterministisch oder nicht deterministisch markiert sind, je nachdem, welche Build-Infunctions sind innerhalb des Körpers verwendet.Erstellen nichtdeterministischer Funktionen in SQL Server mit RAND()

RAND() ist unter den nichtdeterministischen Funktionen aufgelistet (siehe msdn article). Warum kann ich es nicht in einer Funktion verwenden?

Antwort

13

Weil es Nebenwirkungen hat.

Konstrukte mit Nebenwirkungen sind in einer Funktion nicht erlaubt. Der Nebeneffekt, den es hat, ist, einen internen Zustand zu ändern, der den letzten ausgegebenen Wert rand() überwacht.

Ich denke, Sie können es umgehen, indem Sie es in eine View-Definition und wählen Sie dann aus der Ansicht.

+0

ah, jetzt verstehe ich! Ich habe nicht über die interne Speicherung der letzten Zufallszahl nachgedacht. Ich kann sehen, wie dies ihn von anderen nichtdeterministischen Funktionen unterscheidet. Vielen Dank! – BG100

+0

check out http://sqlfascination.com/tag/randomstring/ Es sagt Ihnen genau, wie dies zu tun ist. – baash05

19

Die Verwendung einer Ansicht funktioniert möglicherweise für Sie.
Von Returning Random Numbers from a select statement

CREATE VIEW vRandNumber 
AS 
SELECT RAND() as RandNumber 

Der Blick ist notwendig, weil, wie Sie bereits herausgefunden, ein UDF die Funktion rand() nicht, weil verwenden kann, dass die Funktion nicht determistic machen würde. Sie können die UDF dazu bringen, eine Zufallszahl mithilfe einer Ansicht zu akzeptieren.

CREATE FUNCTION RandNumber() 
RETURNS float 
AS 
    BEGIN 
    RETURN (SELECT RandNumber FROM vRandNumber) 
    END 

Schließlich können Sie diese Funktion in jeder SELECT verwenden, um jetzt eine Zufallszahl zwischen 0 und 1 pro Zeile zurück:

SELECT dbo.RandNumber(), * 
FROM Northwind..Customers 
+4

+1 Für den View-Trick. Daran habe ich mich auch gerade erinnert. Es ist jedoch nicht wegen des Determinismus. 'getdate()' ist in einer Funktion erlaubt. Offensichtlich kann diese Funktion dann nicht verwendet werden, wenn eine deterministische Funktion benötigt wird, wie etwa eine persistente berechnete Spalte. Es ist wegen der Nebenwirkungen. Der Fehler, der ausgelöst wird, ist "ungültige Verwendung eines Seiteneffektoperators 'Rand' innerhalb einer Funktion". –

+0

Danke! Ich hatte davon gehört, dass dies eine Arbeit für die NEWID() - Funktion war, wusste aber nicht, dass es auch für RAND() funktionieren würde. – BG100

3

ich diesen solution gefunden, die keine Aussicht schafft:

Grundsätzlich

:

Statt

SET @R = Rand() 

Verwenden

SET @R = ABS(CHECKSUM(PWDENCRYPT(N'')))/2147483647.0 

In meinem Fall wollte ich eine Zahl zwischen 1 und 10:

ROUND(((10 - 1 -1) * (ABS(CHECKSUM(PWDENCRYPT(N'')))/2147483647.0) + 1), 0)) 

ROUND(((@max - @lower -1) * (ABS(CHECKSUM(PWDENCRYPT(N'')))/2147483647.0) + @lower), 0)) 

Wenn Sie eine vollständige Erklärung wollen: Using (Or Simulating) Rand() In A T-Sql User-Defined Function