HQL - 删除并出现 JOIN 错误

HQL - Delete with JOIN error

我正在尝试使用 join 执行 HQL 删除。搜索后我发现我需要创建一个查询,就像这里建议的那样:

http://dasunhegoda.com/1093-you-cant-specify-target-table-table_name-for-update-in-from-clause/104/

这是我的查询:

    dao.executeByHql(
        "DELETE FROM FinalGradeResult e WHERE e.id IN "
        + "( SELECT id FROM "
            + "( SELECT x FROM FinalGradeResult x " 
            + "where x.student.id = :studentId "
            + " AND x.classDiscipline IN " + 
                + "(SELECT cd from ClassDiscipline cd " 
                + " where cd.clazz.id = :clazzId ) ) as X )",
    new HqlParameter("studentId", student.getId()), 
    new HqlParameter("clazzId", from.getId()));

但是我一直收到这个错误:

org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token:( near line 1, column 94 [DELETE FROM xxxxxxxxxxxx.entity.FinalGradeResult e WHERE e.id IN ( SELECT id FROM ( SELECT x FROM xxxxxxxxxxxxxxx.entity.FinalGradeResult x where x.student.id = :studentId AND x.classDiscipline IN (SELECT cd from xxxxxxxxxxxxxxxx.entity.ClassDiscipline cd where cd.clazz.id = :clazzId ) ) as X )]

错误指出第二个 ( 是错误的,紧接着"SELECT id FROM"

编辑 我试过这样,但出现了同样的错误:

    dao.executeByHql(
        "DELETE FROM FinalGradeResult e WHERE e.id IN "
        + "( SELECT id FROM "
        + "( SELECT x FROM FinalGradeResult x "
            + " where x.student.id = :studentId "
            + " AND x.classDiscipline.clazz.id = :clazzId )"
        + " as X )",

编辑 2:由于我在这个问题中发布的 link 中描述的问题,这样的查询不起作用:

dao.executeByHql(
        "DELETE FROM FinalGradeResult  e WHERE e.id IN " + "( SELECT x.id FROM FinalGradeResult as x "
                + " where x.student.id = :studentId " + " AND x.classDiscipline.clazz.id = :clazzId )",
        new HqlParameter("studentId", student.getId()), new HqlParameter("clazzId", from.getId()));

错误是:

Caused by: java.sql.SQLException: You can't specify target table 'tb_final_grade_result' for update in FROM clause

解决方案

在尝试了所有方法之后,我们的结论是:

所以我决定使用NativeSQL来解决问题:

dao.executeBySQL(
        "   delete from tb_final_grade_result where id in "
                + " (select * from ( select finalgrade1_.id from tb_final_grade_result finalgrade1_ cross join tb_class_discipline classdisci2_ "
                + " where finalgrade1_.id_class_discipline=classdisci2_.id and finalgrade1_.id_student= :studentId and classdisci2_.id_class= :clazzId ) as tmp )",
        new HqlParameter("studentId", student.getId()), new HqlParameter("clazzId", from.getId()));

特别感谢@scaisEdge

可能是因为X的位置不对

并且您正在重复 x 而不是列名(使用正确的列名设置 ***column_name***

"DELETE FROM FinalGradeResult e WHERE e.id IN "
 + "( SELECT id  FROM 
    ( SELECT ***column_name ***  FROM FinalGradeResult x where x.student.id = :studentId AND x.classDiscipline IN 
    (SELECT cd from ClassDiscipline cd where cd.clazz.id = :clazzId ) as X)  )",

如果 sibquery 在 hibernate 中不起作用,请尝试使用 join

进行简单查询
  DELETE FROM FinalGradeResult e 
  WHERE e.id in ( 
     SELECT  id FROM FinalGradeResult x 
     JOIN ClassDiscipline cd ON ( cd.cd.clazz.id = :clazzId  
                  and  x.classDiscipline = cd.ClassDiscipline )
     WHERE  x.student.id = :studentId);

为什么您需要在要删除的 table 上使用 in (select?不能把条件放在where子句里吗?

DELETE FROM FinalGradeResult  e WHERE e.student.id = :studentId " + " AND e.classDiscipline.clazz.id = :clazzId )",
    new HqlParameter("studentId", student.getId()), new HqlParameter("clazzId", from.getId()));

此外,我不确定您指的参数 classDiscipline.clazz.id 是什么? classDiscipline 其他实体是否有一个名为 clazz 的字段是另一个实体?这就是查询的意思。

您的原始查询的问题在于,除了 select 和 where 子句之外,您不允许在任何地方使用内部 select。因为 HQL 根据实体而不是表或列进行操作,所以 select 从表的子集进行操作没有意义。见 here:

Note that HQL subqueries can occur only in the select or where clauses.

我们在我们的项目中遇到了类似的问题,我努力寻找一个单一的查询解决方案,但我担心 MySQL 由于 HQL 的语言设计,这是不可能的。

我想到的最好办法是首先将 ID 作为列表获取,然后将该列表作为列表参数传递给您的更新。对你来说可能是这样的:

Query idQuery = createQuery("select id from FinalGradeResult gr where gr.student.id = :studentId AND gr.classDiscipline IN (SELECT cd from ClassDiscipline cd where cd.clazz.id = :clazzId"));
//add parameters
List<Number> ids = query.list();
Query entityQuery = createQuery("delete from FinalGradeResult where id in (:ids)");
entityQuery.setParameterList("ids", ids);

query.executeUpdate()

解决方案

在尝试了所有方法之后,我们的结论是:

  • 我们不能直接只有一个查询,因为我们不能在 DELETE 上进行连接。

  • 我们不能只有 2 个查询(一个子查询),因为我们有一个 MYSQL BUG(在提供的 link 中描述)

  • 我们不能有 3 个查询(2 个子查询),因为我们不能在 FROM 子句中有子查询。这就是为什么我们的第二个查询不起作用 (select * from (select ...)) 无效。

所以我决定使用NativeSQL来解决问题:

dao.executeBySQL(
        "   delete from tb_final_grade_result where id in "
                + " (select * from ( select finalgrade1_.id from tb_final_grade_result finalgrade1_ cross join tb_class_discipline classdisci2_ "
                + " where finalgrade1_.id_class_discipline=classdisci2_.id and finalgrade1_.id_student= :studentId and classdisci2_.id_class= :clazzId ) as tmp )",
        new HqlParameter("studentId", student.getId()), new HqlParameter("clazzId", from.getId()));