CREATE PROCEDURE [SelectRandomData] (
@targetCount INT
)
AS BEGIN
DECLARE @t TABLE (id INT)
-- vygenerovat posloupnost 0,1,2,3... tak dlouhou, aby počet záznamů v tabulce * počet čísel byl víc, než chceme záznamů na výsledku
DECLARE @i INT, @count INT
SET @i = 0
SELECT @count = COUNT(*) FROM tabulka
WHILE (@i <= @targetCount / @count) BEGIN
INSERT INTO @t (id) VALUES (@i)
SELECT @i = @i + 1
END WHILE
-- vrátit výsledky
SELECT TOP (@targetCount) t0.*
FROM tabulka t0
JOIN @t t1 ON 1 = 1
ORDER BY NEWID()
END
Tohle by mělo být rychlé, protože to nepoužívá kurzory (ty extrémně zpomalují). Protože záznamy z tabulky tam mají být víckrát, musíme je "namnožit" pomocí JOINu s jinou tabulkou (JOIN dělá dvojice každý s každým tak, aby to vyhovovalo jeho podmínce, vzhledem k tomu, že za ON je 1 = 1, tak to prostě vezme každý záznam z tabulky tabulka a každý záznam z @t a vygeneruje to všechny dvojice). Na začátku si jen zjistíme, kolik potřebujeme záznamů a kolik jich máme, a podle toho si vygenerujeme tabulku @t (je úplně jedno, co v ní bude, jde o počet řádků) tak, aby nám JOIN se skutečnou tabulkou dal dostatek záznamů (víc než jich potřebujeme na výstup). Pak už jen z toho JOINu vybereme prvních @targetCount záznamů a seřadíme je podle NEWID (nový guid, což je pseudonáhodná hodnota), takže je dostaneme v náhodném pořadí. Nebude to úplně přesná matematická náhoda (to by tabulka @t musela mít vždy @targetCount prvků, což asi nebude příliš efektivní). Kdybych v taulbce tabulka měl řekněme čísla od 1 do 10 a chtěl vybrat 20 prvků, tak každé číslo bude v JOINu jen dvakrát (resp. třikrát, je tam <=). Kdybych chtěl pravou náhodu, musím připustit i situaci, kdy si vyberu 20x jedničku, což tady nejde. Leda že by @t obsahovala 20 čísel, ale to by u velkých množin bylo náročné na paměť. P.S. Píšu z hlavy, asi v tom SQL budou chyby.
|