Использование UNION в синтаксисе django ORM между различными классами в одной иерархии - PullRequest
1 голос
/ 31 мая 2011

Мне нужно реализовать что-то вроде

 (SELECT table1.*, val=2 FROM table1 INNER JOIN table2 ON table1.id = table2.id WHERE some_condition)
 UNION
 (SELECT table1.*, val=3 FROM table1 INNER JOIN table3 ON table1.id = table3.id WHERE some_condition)

или

 (SELECT val1, val2, val3, val=2 FROM table2 WHERE some_condition)
 UNION
 (SELECT val1, val2, val3, val=3 FROM table3 WHERE some_condition)

Т.е. иметь класс 'table1', 'table2' и 'table3', где table2 и table3 получены изtable1 Мне нужно выбрать все из них с дополнительным полем.Проблема в том, что я бы предпочел избегать использования необработанных SQL-запросов, так как some_condition должно использоваться повторно.Если я пытаюсь использовать дополнительные, он жалуется, что я использую .extra.

Ответы [ 3 ]

1 голос
/ 01 июня 2011

Вы потратите много времени на борьбу с API django ORM, если попытаетесь написать этот JOIN / UNION вне вызова .execute. Если это будет очень распространенным явлением, рассмотрите возможность использования VIEW, а затем просто выполните SELECT из вновь созданного VIEW.

0 голосов
/ 01 июня 2011

Я решил портировать на sqlalchemy - моя проблема плохо вписывается в django, и я счастлив с tg2 (это говорит о том, что это не значит, что django плохой - он просто плохо подходит для моей задачи).

0 голосов
/ 31 мая 2011

Вы можете переписать его как подзапрос:

select val1, val2, val3, val4
from (
     SELECT val1, val2, val3, val=2 as val4 FROM table2
     UNION
     SELECT val1, val2, val3, val=3 as val4 FROM table3
     ) t
where some_condition

Однако будьте осторожны, потому что это не обязательно лучший вариант.

Это может вас устроить, потому что вы избежали переписать условие, но для планировщика запросов два запроса могут быть очень разными животными.Postgres иногда достаточно умен, чтобы вставлять условия в под-операторы, но один случай, который я никогда не видел, - это когда под-оператор имеет какие-либо агрегаты.

В частности, если условие помещеноснаружи (как показано выше), вы начнете с добавления двух целых таблиц.Затем вы агрегируете их, чтобы исключить дубликаты (это шаг, которого вы избежите, используя union all вместо union, кстати), и вы, наконец, отфильтруете строки в результирующем наборе, соответствующие вашему условию.

Для сравнения, при размещении внутри отдельных битов вы добавляете и сортируете два меньших набора строк.Это будет намного быстрее и будет занимать гораздо меньше памяти.

Короче говоря, фильтруйте строки как можно раньше в своих запросах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...