Погружаемся в глубокую воду с помощью Subquery. У меня есть набор Carpark
s. Carpark
имеют несколько Booking
. В бронированиях есть много BarrierActivity
записей, которые представляют собой различные приходы и уходы на барьерах. Это все простые FK вверх по стеку.
Бронирование может быть получено, а камеры барьера не его распознают. Сотрудник звонит им, но это означает, что система по какой-то причине вышла из строя. И это то, что я пытаюсь сделать здесь. Выясните, какой процент моих бронирований был получен с помощью автоматических средств. Я знаю, что есть несколько других способов сделать это, но я хотел бы сделать это с помощью одного набора запросов на основе подзапроса.
Моя цель достаточно проста. Аннотируйте 0 или 1, чтобы показать, существует ли «запись» BarrierActivity
для каждого Booking
. Аннотируйте среднее значение этих значений за Carpark
.
Первая часть неплохая. Я могу сделать простое Exists()
между BarrierActivity
и Booking
, и тогда каждое бронирование будет иметь 0 или 1:
successful_bas = BarrierActivity.objects.order_by().filter(
booking=OuterRef('pk'),
activity_type=BarrierActivity.TYPE_ANPR_BOOKING,
direction='entry'
).values('booking')
Booking.objects.order_by().annotate(
entry_success=Exists(successful_bas)
)
И опять же, это работает нормально. Но как только я попытаюсь масштабировать это еще на один слой (поэтому смотрю на Carpark
вместо Booking
)...
successful_bas = BarrierActivity.objects.order_by().filter(
booking=OuterRef('pk'),
activity_type=BarrierActivity.TYPE_ANPR_BOOKING,
direction='entry'
).values('booking')
bookings = Booking.objects.order_by().filter(
carpark=OuterRef('pk')
).values('carpark').annotate(
entry_success=Exists(successful_bas)
).values('entry_success')
Carpark.objects.order_by().annotate(
entry_hitrate=ExpressionWrapper(
Avg(Cast(Subquery(bookings), IntegerField())) * 100,
output_field=FloatField()
)
)
... Я получаю подзапрос-ошибка-ошибки: more than one row returned by a subquery used as an expression
. Подзапрос bookings
явно возвращает слишком много, но как мне агрегировать это до того, как он попадет в самый внешний подзапрос?
Я пробовал много вещей, но вот реорганизация среднего значения внутри подзапроса. Та же ошибка:
successful_bas = "... as before ..."
bookings = Booking.objects_standard.order_by().filter(
carpark=OuterRef('pk')
).values('site').annotate(
entry_success=Exists(successful_bas)
).annotate(
entry_avg=Avg(Cast('entry_success', IntegerField()))
).values('entry_avg')
Carpark.objects.order_by().annotate(
entry_hitrate=ExpressionWrapper(
Subquery(bookings, output_field=FloatField()) * 100,
output_field=FloatField()
)
)