2012-11-18 12 views
8

Powiedz, że mam prostą tabelę z 3 polami: "miejsce", "użytkownik" i "bajty". Załóżmy, że pod jakimś filtrem chcę pogrupować według "miejsca" i dla każdego "miejsca", aby zsumować wszystkie bajty dla tego miejsca i losowo wybrać użytkownika dla tego miejsca (jednolicie od wszystkich użytkowników, którzy pasują do tego miejsca). "gdzie" filtr i odpowiednie "miejsce"). Jeśli byłaby funkcja "wybierz losowo z", zrobiłbym:Losowy agregator SQL

SELECT place, SUM(bytes), SELECT_AT_RANDOM(user) WHERE .... GROUP BY place; 

... ale nie mogłem znaleźć takiej funkcji agregującej. Czy czegoś brakuje? Jaki może być dobry sposób na osiągnięcie tego?

+4

Co to jest RDBMS? –

+0

Nie jestem świadomy żadnego pojedynczego RDBMS z taką funkcją. Większość musi użyć jakiegoś innego mechanizmu, aby osiągnąć ten sam wynik * (Takie jak przypisanie losowej liczby do każdego użytkownika, a następnie wybranie użytkownika o najwyższej wartości). * Ale każdy będzie miał inne możliwości, a każdy będzie działał inaczej. To naprawdę jest pytanie specyficzne dla RDBMS. – MatBailie

+0

Jeśli używasz MySQL, po prostu napisz nieprawidłowy "GROUP BY" (np. Nie stosuj agregatu na użytkownika) i wybierze on wiersz losowo. –

Odpowiedz

5

Jeśli Twój RDBMS obsługuje funkcje analityczne.

WITH T 
    AS (SELECT place, 
       Sum(bytes) OVER (PARTITION BY place) AS Sum_bytes, 
       user, 
       Row_number() OVER (PARTITION BY place ORDER BY random_function()) AS RN 
     FROM YourTable 
     WHERE ....) 
SELECT place, 
     Sum_bytes, 
     user 
FROM T 
WHERE RN = 1; 

Dla SQL Server Crypt_gen_random(4) lub NEWID() byłoby przykłady czegoś, co może być podstawiony w za random_function()

2

myślę, że pytanie jest DBMS specyficzny. Jeśli DBMS jest MySQL, można użyć takiego rozwiązania:

SELECT place_rand.place, SUM(place_rand.bytes), place_rand.user as random_user 
FROM 
    (SELECT place, bytes, user 
    FROM place 
    WHERE ... 
    ORDER BY rand()) place_rand 
GROUP BY 
    place_rand.place; 

rozkazy podzapytanie rekordy w kolejności losowej. Zewnętrzne grupy zapytań przez place, sumuje się bytes i zwraca pierwszego losowego użytkownika, ponieważ użytkownik nie jest w funkcji agregującej ani w klauzuli group by.

0

zrobiłbym trochę zmienności na Marcina rozwiązania:

select place, sum(bytes), max(case when seqnum = 1 then user end) as random_user 
from (select place, bytes, 
      row_number() over (partition by place order by newid()) as sequm 
     from t 
    ) t 
group by place 

(Gdzie newid() jest tylko jeden sposób, aby uzyskać liczbę losową, w zależności od bazy).

Dla niektórych powód, ja preferuję to podejście, ponieważ wciąż ma funkcję agregacji w zapytaniu zewnętrznym. Jeśli podsumowujesz kilka pól, wydaje mi się to czystsze.

0

z niestandardowych zagregowanej funkcji, można napisać wyrażenia proste:

SELECT place, SUM(bytes), SELECT_AT_RANDOM(user) WHERE .... GROUP BY place; 

SELECT_AT_RAMDOM byłaby funkcja zwyczaj kruszywo.

Tutaj jest dokładnie an implementation w PostgreSQL.