2016-03-27 9 views
0

Sagen wir, ich habe eine Item-Tabelle mit Artikeldatensätzen, jeder Artikel kann zu einer oder mehreren Kategorien gehören. Jede Kategorie hat ein oder mehrere Elemente in ihnenPostgreSQL: Wählen Sie zufällige Datensätze, die einschränkende Bedingung (en) erfüllen

Wie würde ich eine zufällige Liste von einzigartige Artikel, die den Zustand wie 5 Artikel aus Kategorie A, 3 Artikel aus Kategorie B, 4 Artikel aus Kategorie C etc und auch die Reihenfolge der Kategorie beibehalten, dh A -> B -> C

Die sort_order und pro Kategorie item_count für die Abfrage wird in einer anderen Tabelle gespeichert.

Die Artikeltabelle ist ziemlich groß ~ 1 Million Zeilen, die Artikel, die die Bedingung erfüllen, können ziemlich große Lücken haben. so etwas wie dieses

Antwort

1

Sie können versuchen:

SELECT item_id FROM (
    ((SELECT t.category,t.item_id from items t where t.category ='A' order by random() limit 5) 
    UNION 
    (SELECT t.category,t.item_id from items t where t.category ='B' order by random() limit 3) 
    UNION 
    (SELECT t.category,t.item_id from items t where t.category ='C' order by random() limit 4)) 
ORDER BY category 

Ich kann Ihnen nicht versprechen, dass schnell sein, aber es sollte funktionieren.

1

Ich würde geneigt sein, dies zu tun mit einem join, wie folgt aus:

select i.* 
from (select i.*, row_number() over (partition by category order by random()) as seqnum 
     from items i 
    ) i join 
    (select 'A' as category, 5 as num union all 
     select 'B' as category, 3 as num union all 
     select 'C' as category, 4 as num 
    ) l 
    on i.category = l.category 
where i.seqnum <= l.num; 

Dies ist jedoch nicht das Problem für einzigartige Artikel löst. Das gleiche Objekt könnte also mehr als einmal in der Liste erscheinen. Unter der Annahme, dass es genügend Elemente für diese Anforderung sind, würde ich zuerst für jedes Element eine zufällige Kategorie auswählen und die gleiche Logik folgen:

select i.* 
from (select i.itemid, min(category) as category, 
      row_number() over (partition by min(category) 
           order by random() 
           ) as seqnum 
     from items i 
     group by i.itemid 
    ) i join 
    (select 'A' as category, 5 as num union all 
     select 'B' as category, 3 as num union all 
     select 'C' as category, 4 as num 
    ) l 
    on i.category = l.category 
where i.seqnum <= l.num; 

Die Verwendung von min() ist eine Art von Hack eine Kategorie pro Stück zu bekommen.