【问题标题】:QueryDsl SQL - Left Join a subqueryQueryDsl SQL - 左连接子查询
【发布时间】:2019-04-08 19:14:51
【问题描述】:

我正在使用 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 中几乎很重要,因为这只是整个复杂查询的一个sn-p。

  1. 我该如何处理LEFT JOIN x ON部分

  2. SELECT payoutBbf.totalPyts部分中的子查询别名如何处理

【问题讨论】:

标签: java mysql spring-data querydsl


【解决方案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.idNumberPath&lt;Long&gt;,请使用:Expressions.numberPath(Long.class, payoutBbf, mmbId)
  • 这怎么编译?这在querydsl 5中仍然可能吗?将子查询作为参数放在 leftJoin 中并带有一个元组以 Cannot resolve method 'leftJoin(com.querydsl.jpa.JPQLQuery&lt;T&gt;, com.querydsl.core.types.dsl.StringPath)'
  • @nailer_boxer 我已经有一段时间没有使用 querydsl 了,所以我需要很长时间来测试它;但从您的错误来看,您似乎正在使用带有 JPA 的 querydsl;我没有使用 JPA。
  • @raven,是的,我将它与 JPA 一起使用,所以我想这就是问题所在。无论如何,谢谢你:)。我找到了另一个适合我的解决方案。如果我有时间的话,我可能会在明天发布它,以防其他人为此而苦恼。
【解决方案2】:

我认为这对你有用。不过这有点 hacky:

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
  • 对我的项目来说可能太“hacky”了。但很高兴看到这个问题会有解决方案,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-02
  • 1970-01-01
  • 2021-12-25
  • 2010-09-12
  • 2016-10-18
  • 2016-06-08
  • 1970-01-01
相关资源
最近更新 更多