Вычитание двух SELECT в другом SELECT в SQLAlchemy?

Я пытаюсь вычесть результаты двух разных вызовов select в SQLAlchemy как еще один select, чтобы, наконец, вызвать order_by для воссоздания следующего запроса:

SELECT reviews.id FROM reviews
ORDER BY (
    SELECT (
        SELECT COUNT(*) FROM review_upvoters WHERE review_id = reviews.id
    ) - (
        SELECT COUNT(*) FROM review_downvoters WHERE review_id = reviews.id
    )
);

Я пытался просто вычесть два выбора друг из друга (query_one - query_two), два безрезультатно и просмотреть документы SQLAlchemy, но они точно не помогли.

В настоящее время у меня есть следующее:

upvoters_count = select([func.count()]).where(ReviewUpvoters.review_id == Review.id)
downvoters_count = select([func.count()]).where(ReviewDownvoters.review_id == Review.id)
reviews = Reviews.query.order_by(...)

где я пытаюсь выяснить внутреннюю часть order_by, чтобы правильно вычесть эти selects.

(Если Reviews.query выглядит странно, это потому, что я использую Gino для асинхронной поддержки Postgres, но по большей части он использует обычные объекты SQLAlchemy, поэтому это не должно ни на что влиять.)

Поскольку __sub__, похоже, не определен для Select объектов, я немного озадачен этим, и я не на 100% заинтересован в реструктуризации таблиц, чтобы эти две таблицы находились в одной таблице с чем-то, чтобы их различать.

не уверен в этом: попробуйте Reviews.query.order_by(upvoters_count.as_scalar() - downvoters_count.as_scalar())docs.sqlalchemy.org/en/latest/core/…

Tryph 06.04.2019 16:12

@Tryph сладкий, кажется, работает отлично.

Ovyerus 07.04.2019 04:40
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
1 124
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Почему бы немного не реорганизовать этот запрос? Я думаю, что это было бы быстрее, и это определенно упростило бы то, что вы должны просить sqlalchemy сделать.

SELECT reviews.id
FROM reviews
LEFT JOIN review_upvoters ON reviews.id = review_upvoters.review_id
LEFT JOIN review_downvoters ON reviews.id = review_downvoters.review_id
GROUP BY reviews.id
ORDER BY
COUNT(DISTINCT review_upvoters.id) - COUNT(DISTINCT review_downvoters.id)
;

Судя по моему тестированию, это не дает того же результата, что и исходный запрос gist.github.com/Ovyerus/dfe1a49966fed5b982d3d7417f63939e.

Ovyerus 07.04.2019 04:26

Я считаю, что вам понадобится COUNT (DISTINCT), так как происходит два соединения

Stephen Fuhry 08.04.2019 13:07
Ответ принят как подходящий

Благодаря @Tryph я заработал, используя as_scalar() в подзапросах.

upvoters_count = select([func.count()]).where(ReviewUpvoters.review_id == Review.id).as_scalar()
downvoters_count = select([func.count()]).where(ReviewDownvoters.review_id == Review.id).as_scalar()
query = Reviews.query.order_by(upvoters_count - downvoters_count)

который производит следующий запрос, который сопоставим с моим исходным

SELECT reviews.id, reviews.created_at, reviews.rating, reviews.content, reviews.title, reviews.mod_id, reviews.author_id
FROM reviews
ORDER BY (
    SELECT count(*) AS count_1
    FROM review_upvoters
    WHERE review_upvoters.review_id = reviews.id
) - (
    SELECT count(*) AS count_2
    FROM review_downvoters
    WHERE review_downvoters.review_id = reviews.id
);

Другие вопросы по теме