Я использую QueryDsl SQL
и хочу left join
подзапрос. Вот простой запрос SQL
SELECT
usr.memberId,
payoutsBbf.totalPyts
FROM
users usr
LEFT JOIN
(SELECT
pyt.member_id AS mmb_id,
SUM(pyt.amount) AS totalPyts
FROM
payout pyt
WHERE
pyt.payoutPeriod < '2018-01-01'
GROUP BY pyt.member_id) AS payoutsBbf ON usr.id = payoutsBbf.mmb_id
Я хочу написать это в QueryDsl SQL
, и почти важно, чтобы подзапрос оставался присоединенным к основной таблице users
, потому что это всего лишь фрагмент всего сложного запроса.
Как мне быть с частью LEFT JOIN x ON
Как мне работать с псевдонимом подзапроса в части SELECT payoutBbf.totalPyts
Проблема здесь в том, что я leftJoin-ing
QUsers
для подзапроса. С Q
-классом я могу использовать точечную нотацию для записи .leftJoin(subquery).on(qusers.id.eq(??)
, но я столкнулся с проблемой в части подзапроса on
Ответ на похожий вопрос: stackoverflow.com/a/67254869/3308908
Я думаю, это сработает для вас. Это немного взломано:
SQLQueryFactory sqlqf; // Should be @Autowired
QUsers qusers = new QUsers();
QPayouts qpayouts = new QPayouts();
Expression<Long> memberId = ExpressionUtils.as(qpayouts.memberId, "mmb_id");
Expression<Double> totalPayouts = ExpressionUtils.as(qpayouts.amount.sum(), "totalPayouts");
SQLQuery<Tuple> payoutsBbf = SQLExpressions.select(memberId, totalPayouts)
.from(qpayouts)
.where(qpayouts.payoutPeriod.lt("2018-01-01")) // Use date object
.groupBy(qpayouts.memberId);
final SimplePath<? extends SQLQuery> payoutsBBfPath = Expressions.path(payoutsBBfPath.getClass(), "payoutsBbf");
List<Tuple> fetch = sqlqf.select(
qusers.memberId,
Expressions.path(payoutsBbf.getClass(), new PathMetadata(payoutsBBfPath, "totalPayouts", PathType.PROPERTY))
)
.from(qusers)
.leftJoin(payoutsBbf, payoutsBBfPath)
.addJoinFlag(" on payoutsBbf.mmb_id = users.id", JoinFlag.Position.BEFORE_CONDITION)
.fetch();
Обратите внимание на использование JoinFlag для указания столбца соединения с использованием псевдонима, определенного как payoutsBbf
. Также обратите внимание на использование Expressions.path()
для указания подстолбцов в разделе select()
.
что такое groupBy.getClass()?
Это должно быть payoutsBBfPath.getClass() , я отредактировал ответ, чтобы отразить это
какая это версия? Я не могу найти addJoinFlag
метод
Использование версии 4.2.1
вот как бы я это сделал:
final StringPath payoutsBbf = stringPath("payoutsBbf");
final String mmbId = "mmb_id";
final String totalPyts = "totalPyts";
sqlQueryFactory.select(users.memberId, stringPath(payoutsBbf, totalPyts))
.from(users).leftJoin(
sqlQueryFactory.select(payout.member_id.as(mmbId), member_id.amount.sum().as(totalPyts))
.from(payout).where(payout.payoutPeriod.lt("2018-01-01")).groupBy(payout.member_id),
payoutsBbf
).on(users.id.eq(stringPath(payoutsBbf, mmbId))).fetch();
Это было очень просто. Вы спасатель жизни. Спасибо
Для тех, кому интересно, как был создан StringPath
: Expressions.stringPath("payoutBbf");
Expressions.stringPath(payoutBbf, totalPyts)
... а также, поскольку users.id
является NumberPath<Long>
, используйте это: Expressions.numberPath(Long.class, payoutBbf, mmbId)
Как это вообще компилируется? Это все еще возможно в querydsl 5? Помещение подзапроса в качестве аргумента в leftJoin с кортежем заканчивается Cannot resolve method 'leftJoin(com.querydsl.jpa.JPQLQuery<T>, com.querydsl.core.types.dsl.StringPath)'
@nailer_boxer Я некоторое время не работал с querydsl, поэтому мне потребовалось бы много времени, чтобы протестировать его; но из вашей ошибки кажется, что вы используете querydsl с JPA; Я не использовал JPA.
@raven, да, я использую его с JPA, так что, думаю, проблема в этом. В любом случае, спасибо :). Я нашел другое решение, которое меня устраивает. Я опубликую его, может быть, завтра, если у меня будет время, на случай, если кто-то еще борется с этим.
.leftJoin
querydsl.com/static/querydsl/latest/reference/html/…