2013-07-02 16 views
5

Ich benutze Microsoft SQL Server 2008. Ich muss nach einem Fremdschlüssel aggregieren, um zufällig einen einzelnen Wert zu erhalten, aber ich bin ratlos. Betrachten Sie die folgende Tabelle:Aggregat nach dem Zufallsprinzip?

id   fk   val 
----------- ----------- ---- 
1   100   abc 
2   101   def 
3   102   ghi 
4   102   jkl 

Das gewünschte Ergebnis wäre:

fk   val 
----------- ---- 
100   abc 
101   def 
102   ghi 

Wo die val für fk 102 zufällig sein würde, entweder "ghi" oder "jkl".

Ich versuchte, NEWID() zu verwenden, um eindeutige zufällige Werte zu erhalten, jedoch schlägt der JOIN fehl, da der NEWID() - Wert abhängig von der Unterabfrage unterschiedlich ist.

WITH withTable AS (
    SELECT id, fk, val, CAST(NEWID() AS CHAR(36)) random 
    FROM exampleTable 
) 
SELECT t1.fk, t1.val 
FROM withTable t1 
JOIN (
    SELECT fk, MAX(random) random 
    FROM withTable 
    GROUP BY fk 
) t2 ON t2.random = t1.random 
; 

Ich bin ratlos. Irgendwelche Ideen würden sehr geschätzt werden.

+1

@ypercube: Wurde im ersten Satz des Beitrags erwähnt ... –

Antwort

6

Ich könnte darüber ein wenig anders denken, mit einer speziellen Ranking-Funktion namens ROW_NUMBER().

Sie wenden grundsätzlich eine Nummer an, gruppiert nach fk, beginnend mit 1, geordnet nach dem Zufallsprinzip, indem Sie die NEWID() Funktion als Sortierwert verwenden. Daraus können Sie alle Zeilen auswählen, in dem die Zeilennummer 1. Die Wirkung dieser Technik war, ist, dass es randomisiert, welche Zeile den Wert zugewiesen wird 1.

WITH withTable(id, fk, val, rownum) AS 
(
    SELECT 
     id, fk, val, ROW_NUMBER() OVER (PARTITION BY fk ORDER BY NEWID()) 
    FROM 
     exampleTable 
) 
SELECT 
    * 
FROM 
    withTable 
WHERE 
    rownum = 1 

Dieser Ansatz hat den zusätzlichen Vorteil, dass es darum kümmert die Gruppierung und die Randomisierung in einem Durchgang.

+0

du bist schneller als ich :) aber ich habe ein [SQL FIDDLE EXAMPLE] erstellt (http://sqlfiddle.com/#!6/dc46b/7) –

+0

Danke, wusste nicht über den PARTITION BY-Befehl – user1886415

+3

Seien Sie vorsichtig mit 'NEWID' wie folgt, es ist eine seitenwirksame nicht-deterministische Skalarfunktion mit oft kontraintuitivem Verhalten. Es gibt [sehr wenige Garantien] (http://connect.microsoft.com/SQLServer/feedback/details/350485/bug-with-newid-and-table-expressions) (für die Zukunft) darüber, wie oft Skalarfunktionen sind ausgeführt - oder überhaupt. Der Code hier beruht auf einem bestimmten Verhalten, das beibehalten werden kann oder nicht. Ändern Sie die 'ORDER BY NEWID()' in 'ORDER BY (SELECT NEWID())' um ein Beispiel zu sehen. –

1

Sie können dies nicht mit Aggregation aber mit row_number():

select id, fk, val 
from (select t1.*, 
      row_number() over (partition by fk order by newid()) as seqnum 
     from withTable t1 
    ) t1 
where seqnum = 1 
0

Eine Möglichkeit ist, die Werte zu erhalten, die die gleiche fk in eine temporäre Tabelle sind dann TOP 1 ORDER von NEWID SELECT()

Das sollte für Sie arbeiten.

Verwandte Themen