2

「ユーザーごとに購入したアイテムの平均数、最大数、最小数」を取得するためのクエリを作成しようとしています。

データソースは、次の単純な販売記録テーブルです。

class SalesRecord(models.Model):
    id           = models.IntegerField(primary_key=True)
    user_id      = models.IntegerField()
    product_code = models.CharField()
    price        = models.IntegerField()
    created_at   = models.DateTimeField()

ユーザーが購入したすべてのアイテムについて、このテーブルに新しいレコードが挿入されます。[注]:このバックエンドシステムはユーザー情報を管理しないため、同じデータベース内のテーブルへの外部キーではありませuser_id値は、製品のフロントエンド部分によって提供されます。

クエリを作成する試みは次のとおりです。

q = SalesRecord.objects.all()
q = q.values('user_id').annotate(   # group by user and count the # of records
    count=Count('id'),              # (= # of items)
    ).order_by()
result = q.aggregate(Max('count'), Min('count'), Avg('count'))

コードを実行しようとするとProgrammingError、最後の行でaが発生します。

(1064、「SQL構文にエラーがあります。MySQLサーバーのバージョンに対応するマニュアルで、「FROM(SELECT .AS sales_records、COUNT(.`」の1行目)の近くで使用する正しい構文を確認してください」)user_iduser_idsales_records

Djangoのエラー画面は、SQLが

SELECT FROM
  (SELECT
    `sales_records`.`user_id` AS `user_id`,
    COUNT(`sales_records`.`id`) AS `count`
  FROM `sales_records`
  WHERE (`sales_records`.`created_at` >= %s AND `sales_records`.`created_at` <= %s )
  GROUP BY `sales_records`.`user_id` ORDER BY NULL) subquery

何も選択していません!誰かがこれを行う正しい方法を教えてもらえますか?

Djangoのハッキング

で選択したフィールドのキャッシュをクリアdjango.db.models.sql.query.BaseQuery.get_aggregation()すると、問題が解決するようです。これが修正または回避策であるかどうかはわかりませんが。

@@ -327,10 +327,13 @@
    # Remove any aggregates marked for reduction from the subquery
    # and move them to the outer AggregateQuery.
+   self._aggregate_select_cache = None
+   self.aggregate_select_mask = None
    for alias, aggregate in self.aggregate_select.items():
        if aggregate.is_summary:
            query.aggregate_select[alias] = aggregate
-           del obj.aggregate_select[alias]
+           if alias in obj.aggregate_select:
+               del obj.aggregate_select[alias]

...結果が得られます:

{'count__max': 267, 'count__avg': 26.2563, 'count__min': 1}
4

2 に答える 2

2

モデルをそのまま使用して(FKからユーザーへ)、user_idカウントを取得して、自分で計算を行うことができます。

counts = SalesRecord.objects.values('user_id').\
        annotate(count=Count('id')).values_list('count', flat=True)
(max(counts), min(counts), sum(counts) / float(len(counts)))

外部キーを使用するようにテーブルを変更し、モデルを次のように見せることができた場合:

class SalesRecord(model.Models):
    user = model.ForeignKey(User)
    product_code = models.CharField()
    price        = models.IntegerField()
    created_at   = models.DateTimeField()

次に、Userオブジェクトから問題にアプローチし、aggregate()を使用できます。

users_with_counts = Users.objects.annotate(count=Count('salesrecord'))
stats = users_with_counts.aggregate(Max('count'), Min('count'), Avg('count'))

どちらの方法でも、単一のデータベースクエリで必要なものが得られます。

于 2010-04-01T15:29:11.877 に答える
0

ORMクエリは確かに正しいですが、バグはDjango1.6にあります。どうやらそれは1.7で修正されました。ソース:https ://code.djangoproject.com/ticket/23669#comment:5

于 2014-10-17T10:03:23.337 に答える