Django вычисляет суммарную сумму столбца из базы данных [duplicate]

Ответ

@ brimborium очень хорош (+1 для него), но я просто хочу подробнее рассказать об этом, используя некоторые цифры. Давайте сначала возьмем примитивное назначение:

int a = new Integer(5);
int b = a;
b = b + b;
System.out.println(a); // 5 as expected
System.out.println(b); // 10 as expected
int a = new Integer(5);

1- Первый оператор создает объект Integer значения 5. Затем, назначив его переменной a, объект Integer будет распакован и сохраняются в a в качестве примитива.

После создания объекта Integer и перед назначением:

enter image description here [/g0]

После назначения:

enter image description here [/g1]

int b = a;

2- Это только что прочитает значение a, а затем сохранит его в b.

(Объект Integer теперь имеет право на сбор мусора, но не обязательно собирает мусор в этой точке)

enter image description here [/g2]

b = b + b;

3- Это дважды читает значение b, добавляет их вместе и помещает новое значение в b.

enter image description here [/g3]


На другая сторона:

SomeObject s1 = new SomeObject("first");
SomeObject s2 = s1;
s2.setText("second");
System.out.println(s1.getText()); // second as UNexpected
System.out.println(s2.getText()); // second as expected
SomeObject s1 = new SomeObject("first");

1- Создает новый экземпляр класса SomeObject и назначает его ссылке s1.

enter image description here [/g4]

SomeObject s2 = s1;

2- Это приведет к тому, что ссылка s2 указывает на объект, на который указывает s1. [/ g2 1]

enter image description here [/g5]

s2.setText("second");

3- Когда вы используете сеттеры для ссылки, он будет изменять объект, на который ссылается ссылка.

enter image description here [/g6]

System.out.println(s1.getText());
System.out.println(s2.getText());

4- Оба должны печатать second, так как две ссылки s1 и s2 относятся к одному и тому же объекту (как показано в предыдущем рисунок).

6
задан wrdeman 20 April 2017 в 13:53
поделиться

5 ответов

Из ответа Димы Кудоша и на основе https://stackoverflow.com/a/5700744/2240489 мне пришлось сделать следующее: я удалил ссылку на PARTITION BY в sql и заменил с результатом ORDER BY.

AModel.objects.annotate(
    cumsum=Func(
        Sum('a_number'), 
        template='%(expressions)s OVER (ORDER BY %(order_by)s)', 
        order_by="id"
    ) 
).values('id', 'cumsum').order_by('id', 'cumsum')

Это дает следующий sql:

SELECT "amodel"."id",
SUM("amodel"."a_number") 
OVER (ORDER BY id) AS "cumsum" 
FROM "amodel" 
GROUP BY "amodel"."id" 
ORDER BY "amodel"."id" ASC, "cumsum" ASC

Ответ Димы Кудоша не суммировал результаты, но это было сделано выше.

2
ответ дан Community 15 August 2018 в 17:35
поделиться

Для справки, начиная с Django 2.0, для достижения этого результата можно использовать функцию Window:

AModel.objects.annotate(cumsum=Window(Sum('a_number'), order_by=F('id').Asc()))\
              .values('id', 'cumsum').order_by('id', 'cumsum')
1
ответ дан Campi 15 August 2018 в 17:35
поделиться
  • 1
    Интересно также знать, что функции окна не работают с SqLite3. – Campi 30 March 2018 в 06:42

Вы можете попытаться сделать это с помощью выражения Func .

from django.db.models import Func, Sum

AModel.objects.annotate(cumsum=Func(Sum('a_number'), template='%(expressions)s OVER (PARTITION BY %(partition_by)s)', partition_by='id')).values('id', 'cumsum').order_by('id')
1
ответ дан Dima Kudosh 15 August 2018 в 17:35
поделиться
  • 1
    Спасибо, очень признателен за ваш ответ. Это не сработало для меня, и я опубликовал свою поправку. – wrdeman 20 April 2017 в 12:53

Проверьте

AModel.objects.order_by("id").extra(select={"cumsum":'SELECT SUM(m.a_number) FROM table_name m WHERE m.id <= table_name.id'}).values('id', 'cumsum')

, где table_name должно быть именем таблицы в базе данных.

0
ответ дан itzMEonTV 15 August 2018 в 17:35
поделиться
0
ответ дан Scott Skiles 29 October 2018 в 00:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: