2015-03-30 1 views
0

J'ai une fonction avec plusieurs instructions RETURN QUERY. A la fin, je veux obtenir seulement N enregistrements aléatoires. Si je mets LIMIT max_size à chaque déclaration RETURN QUERY à la fin j'obtiendrai max_size * compte de RETURN QUERY fois.Comment limiter le jeu de résultats avec plusieurs retour QUERY dans postgresql

Version courte de ma fonction:

CREATE OR REPLACE FUNCTION android_getproposedsongs_test(
              IN puserid character varying, max_size int) 
    RETURNS TABLE(sid uuid, method text) AS 
$BODY$ 
DECLARE 
    songCount int; 
BEGIN 

RETURN QUERY 
    SELECT trackid as sid, lower('popular') as method 
    FROM ratingrecord 
    WHERE trackid NOT IN (
     SELECT trackid FROM ratingrecord WHERE userid = puserid) 
    AND ratingrecord.rating > 0 
    GROUP BY trackid 
    HAVING SUM(rating) > 0 
    ORDER BY SUM(rating) DESC 
    LIMIT max_size; 

CREATE TEMP TABLE recommended ON COMMIT DROP 
AS 
SELECT trackid, lower('recommended') 
FROM ratingrecord finalRate 
    INNER JOIN 
    (
     SELECT otherRate.userid AS otherUserId 
      , SUM(myRate.rating * otherRate.rating) as SumRating 
     FROM ratingrecord AS myRate 
     INNER JOIN ratingrecord AS otherRate 
     ON myRate.trackid = otherRate.trackid 
     WHERE myRate.userid = puserid AND myRate.userid != otherRate.userid   
     GROUP BY otherRate.userid 
     HAVING SUM(myRate.rating * otherRate.rating) > 0 
    ) AS userRelations 
    ON finalRate.userid = userRelations.otherUserId 
WHERE finalRate.trackid NOT IN (SELECT trackid FROM ratingrecord WHERE userid = puserid) 
GROUP BY finalRate.trackid 
HAVING SUM(finalRate.rating * userRelations.SumRating) > 0 
ORDER BY SUM(finalRate.rating * userRelations.SumRating) DESC 
LIMIT max_size; 

RETURN QUERY SELECT * FROM recommended; 

-- another RETURN QUERY statements 

END;  
$BODY$ 
LANGUAGE plpgsql VOLATILE; 

Je veux quelque chose comme ORDER BY random() LIMIT max_size au jeu de résultats, mais ne savent pas où le placer.

Répondre

0

Soit vous utilisezUNION ALL pour combiner toutes les sous-requêtes dans SQL pur et ajouter ORDER BY random() LIMIT n une fois à la fin.

Ou vous devez garder une trace du nombre de lignes vous sont retournés dans plpgsql, comme ceci:

CREATE OR REPLACE FUNCTION android_getproposedsongs_test(puserid varchar, max_size int) 
    RETURNS TABLE(sid uuid, method text) AS 
$func$ 
DECLARE 
    song_count int; -- I'd rather not use spurious capitalisation 
    running_ct int := 0; 
    ct   int; 
BEGIN 

RETURN QUERY SELECT ... LIMIT max_size; -- apply to each individual query! 

GET DIAGNOSTICS ct = ROW_COUNT; 
running_ct := running_ct + ct; 
IF running_ct >= max_size THEN 
    RETURN; 
END IF; 

RETURN QUERY SELECT ... LIMIT max_size; 

GET DIAGNOSTICS ct = ROW_COUNT; 
running_ct := running_ct + ct; 
IF running_ct >= max_size THEN 
    RETURN; 
END IF; 

-- another RETURN QUERY statements 

END 
$func$ LANGUAGE plpgsql VOLATILE; 

connexes:

Cependant , ceci ne renvoie que le premierN lignes, pas une sélection aléatoire. Pour atteindre que, retour toutes lignes remplissant les conditions sans limite et appliquer ORDER BY random() LIMIT n à l'étape suivante:

SELECT * 
FROM android_getproposedsongs_test('foo', 3) 
ORDER BY random() LIMIT 123; 

Vous devez être conscient qu'il peut être beaucoup plus cher pour obtenir des lignes au hasard, parce que tous (éventuellement plusieurs) candidats doivent être identifiés en premier. Il peut être beaucoup moins cher de retourner les premières lignes N.