0

我正在为我们的 API 使用 Tastypie,并且一个端点需要显示特定类别中的地点列表。那部分很简单:

class PlaceResource(ModelResource):
    class Meta:
        queryset = Place.objects.all()
        filtering = { 
            'category': ALL
        }

但是假设我有一个limit = 100,我想从每个类别中获得偶数个位置。

例子:

/api/places/?category=1&category=2&category=3&category=4

应该给我 1、2、3 和 4 类别中的 25 个名额。

我知道我可以使用 SQL 来做到这一点,但是如何以最佳方式完成呢?

4

1 回答 1

1

说,我们有一张桌子:

CREATE TABLE place (
   place_id serial primary key
 , place    text
 , cat_id   int);

在 sqlfiddle 上测试设置
您将从category设置中演示的索引中获利。

基本上,我看到了两种不同的方式:

row_number()

WITH x AS (
    SELECT *, row_number() OVER (PARTITION BY category) AS rn
    FROM   place
    WHERE  category IN (1,2,3,4)
    )
SELECT place_id, place, category
FROM   x
ORDER  BY rn
LIMIT  100;
  • 除了相当优雅之外,这个查询随着更多类别而变长的唯一部分是IN子句。
  • 无需计算每个的份额category,这是自动发生的。
  • 如果某个类别的行数少于其份额,则其余部分将由其他类别相同的份额填充。

UNION ALL

(SELECT * FROM place WHERE category = 1 LIMIT 25)
UNION ALL
(SELECT * FROM place WHERE category = 2 LIMIT 25)
UNION ALL
(SELECT * FROM place WHERE category = 3 LIMIT 25)
UNION ALL
(SELECT * FROM place WHERE category = 4 LIMIT 25);
  • 这是原始且非常快的,但对于许多类别来说会变长(尽管不慢)。
  • 使用UNION ALL,不使用UNION
  • 查询的每条腿周围的括号UNION都需要 apply LIMIT
  • 您需要计算每个类别的份额,并决定如何拆分部分份额。
  • 如果某个类别的行数少于其份额,则从查询中获得的行数会更少。
于 2012-11-19T23:35:45.057 回答