【问题标题】:JPA Specification with Subquery exists fails SQL Server syntax具有子查询的 JPA 规范存在失败 SQL Server 语法
【发布时间】:2020-06-12 16:49:15
【问题描述】:

给定 2 个表,设计状态(通过复合键定义唯一状态)和状态组(定义从设计状态到用户组的外部参照记录),我正在尝试实现一个规范,该规范返回给定用户组的设计状态记录。设计状态与状态组是一对多的关系。下面的代码通过 H2 的单元测试产生正确的结果,但在运行时 SQL Server 中失败,','附近的语法不正确。 我追踪到以下select (costatusgr1_.DESIGN_STAT_CD, costatusgr1_.PRODUCT_ID, costatusgr1_.USER_GROUP_ID)

如果这个子句是select * from CO_STATUS_GROUP costatusgr1_,SQL Server 将返回正确的结果。我正在寻求帮助修复我的规范以使用 EXISTS 或 IN 对子查询执行选择。

DDL如下:

create table CO_DES_STATUS
(
    PRODUCT_ID int not null,
    DESIGN_STAT_CD char(2) not null,
    DESIGN_STAT_DESC varchar(30),
    constraint PK_DES_STATUS
        primary key (PRODUCT_ID, DESIGN_STAT_CD)
)
create table CO_STATUS_GROUP
(
    PRODUCT_ID int not null,
    DESIGN_STAT_CD char(2) not null,
    USER_GROUP_ID varchar(8) not null,
    constraint PK_STATUS_GROUP
        primary key (PRODUCT_ID, DESIGN_STAT_CD, USER_GROUP_ID)
)

等效SQL如下:

select ds.* from CO_DES_STATUS ds 
    inner join CO_STATUS_GROUP sg on ds.PRODUCT_ID=sg.PRODUCT_ID and ds.DESIGN_STAT_CD=sg.DESIGN_STAT_CD
where ds.PRODUCT_ID=123 and sg.USER_GROUP_ID='group1'
order by ds.DESIGN_STAT_SEQ_NUM

对每个表和复合键使用实体,CoDesStatus 将一对多链接到 productId 和 designStatCd 上的 CoStatusGroup。

Predicate 方法的规范:

  public Predicate toPredicate(Root<CoDesStatus> root, CriteriaQuery<?> cq,
      CriteriaBuilder criteriaBuilder) {
    Subquery<CoStatusGroup> subquery = cq.subquery(CoStatusGroup.class);
    Root<CoStatusGroup> subqueryFrom = subquery.from(CoStatusGroup.class);
    Join<CoStatusGroup, CoDesStatus> subqueryJoin = subqueryFrom.join(CoStatusGroup_.coDesStatus);
    Predicate isAccessingUserPredicate = criteriaBuilder
        .equal(subqueryFrom.get(CoStatusGroup_.coSecurityUserGroup), this.accessingUserGroup);
    Predicate isProductPredicate = criteriaBuilder.equal(root.get(CoDesStatus_.id).get(CoDesStatusPK_.productId), coProd.getProductId());
    Predicate isParentEntityPredicate = criteriaBuilder
        .equal(subqueryJoin.get(CoDesStatus_.id), root.get(CoDesStatus_.id));
    subquery.select(subqueryFrom).where(isAccessingUserPredicate, isProductPredicate, isParentEntityPredicate);
    return criteriaBuilder.exists(subquery);
  }

Hibernate 查询结果:

Hibernate: select codesstatu0_.DESIGN_STAT_CD as DESIGN_S1_70_, codesstatu0_.PRODUCT_ID as PRODUCT_2_70_, codesstatu0_.DESIGN_STAT_DESC as DESIGN_S5_70_ from CO_DES_STATUS codesstatu0_ where exists (select (costatusgr1_.DESIGN_STAT_CD, costatusgr1_.PRODUCT_ID, costatusgr1_.USER_GROUP_ID) from CO_STATUS_GROUP costatusgr1_ inner join CO_DES_STATUS codesstatu2_ on costatusgr1_.DESIGN_STAT_CD=codesstatu2_.DESIGN_STAT_CD and costatusgr1_.PRODUCT_ID=codesstatu2_.PRODUCT_ID where costatusgr1_.USER_GROUP_ID='group1' and codesstatu0_.PRODUCT_ID=123 and codesstatu2_.DESIGN_STAT_CD=codesstatu0_.DESIGN_STAT_CD and codesstatu2_.PRODUCT_ID=codesstatu0_.PRODUCT_ID)

错误:

WARN  org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 102, SQLState: S0001
ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Incorrect syntax near ','.

【问题讨论】:

  • 您好,您是否尝试使用查询分析器或其他 SQL Server 工具验证生成的查询的语法?
  • 是的,使用 SQL Server 控制台我得到了与描述相同的错误。但是,一旦我将查询更改为where exists(select * from CO_STATUS_GROUP costatusgr1_,它就会按预期工作。错误告诉我此部分中的逗号无效:where exists(select **(costatusgr1_.DESIGN_STAT_CD, costatusgr1_.PRODUCT_ID, costatusgr1_.USER_GROUP_ID)** from CO_STATUS_GROUP costatusgr1_.

标签: java sql-server hibernate jpa subquery


【解决方案1】:

在存在子查询中,最好还是选择一个常量,所以只需使用以下内容:

  public Predicate toPredicate(Root<CoDesStatus> root, CriteriaQuery<?> cq,
      CriteriaBuilder criteriaBuilder) {
    Subquery<Integer> subquery = cq.subquery(Integer.class);
    Root<CoStatusGroup> subqueryFrom = subquery.from(CoStatusGroup.class);
    Join<CoStatusGroup, CoDesStatus> subqueryJoin = subqueryFrom.join(CoStatusGroup_.coDesStatus);
    Predicate isAccessingUserPredicate = criteriaBuilder
        .equal(subqueryFrom.get(CoStatusGroup_.coSecurityUserGroup), this.accessingUserGroup);
    Predicate isProductPredicate = criteriaBuilder.equal(root.get(CoDesStatus_.id).get(CoDesStatusPK_.productId), coProd.getProductId());
    Predicate isParentEntityPredicate = criteriaBuilder
        .equal(subqueryJoin.get(CoDesStatus_.id), root.get(CoDesStatus_.id));
    subquery.select(criteriaBuilder.literal(1)).where(isAccessingUserPredicate, isProductPredicate, isParentEntityPredicate);
    return criteriaBuilder.exists(subquery);
  }

【讨论】:

  • 感谢 Christian 似乎解决了我的问题!
猜你喜欢
  • 2021-09-06
  • 2012-10-14
  • 1970-01-01
  • 1970-01-01
  • 2014-11-03
  • 1970-01-01
  • 2017-04-12
  • 2011-09-26
  • 1970-01-01
相关资源
最近更新 更多