2016-03-27 19 views
0

Öğe kayıtlarının bulunduğu bir Öğe tablosuna sahip olduğumu söyleyelim, Her öğe bir veya daha fazla kategoriye ait olabilir. Her kategoride bir veya daha fazla öğe vardırPostgreSQL: Sınırlama koşullarını karşılayan rastgele kayıtlar seç

A Kategorisinden 5 öğe, B Kategorisinden 3 öğe, Kategori C vb. 4 öğe gibi koşula uyan benzersiz öğenin rastgele bir listesini nasıl seçerim ve aynı zamanda A -> B -> C

kategorisinin sırasını koruyarak sorgu için sort_order ve kategori item_count'u başka bir tabloda saklanır.

Öğe tablosu oldukça büyüktür ~ 1 milyon satır, koşulu karşılayan öğeler oldukça büyük boşluklara sahip olabilir.

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 

ben hızlı olacağını söz veremem, ancak çalışması gerekir:

cevap

1

Böyle bir şey deneyebilirsiniz.

1

böyle bir join ile bunu meyilli olacaktır:

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; 

Ancak bu benzersiz öğeler için sorunu çözmez. Yani, aynı öğe listede bir defadan fazla görünebilir. Bu istek için yeterli ürün olduğunu varsayarsak, ben ilk her öğe için rasgele kategorisini seçin ve aynı mantığı takip edecek:

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; 

min() kullanımı ürün başına bir kategori almak için bir hack tür.