HQL - 使用JOIN错误删除

时间:2016-04-01 18:35:04

标签: java mysql hibernate hql sql-delete

我试图用连接执行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 :由于我在此问题中发布的链接中描述的问题,这样的查询无效:

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

在尝试了所有内容后,我们得出结论:

  • 我们直接只有一个查询,因为我们无法在DELETE上加入。
  • 我们不能只有2个查询(一个子查询),因为我们有一个MYSQL BUG(在提供的链接中描述)
  • 我们不能有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()));

特别感谢@scaisEdge

4 个答案:

答案 0 :(得分:4)

为什么需要在要删除的同一个表上使用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的字段是另一个实体的其他实体?这就是查询似乎在说的内容。

答案 1 :(得分:2)

原始查询的问题在于,您不允许在select和where子句中的任何位置进行内部选择。因为HQL根据实体而不是表或列进行操作,所以从表的子集中进行选择是没有意义的。见here

  

请注意,HQL子查询只能出现在select或where子句中。

我们在项目中遇到了类似的问题,我一段时间都在努力寻找单一的查询解决方案,但我担心MySQL因为HQL的语言设计而无法实现。< / p>

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

--fork-point

答案 2 :(得分:1)

可能是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);

答案 3 :(得分:0)

解决方案

尝试了一切之后,我们的结论是:

  • 我们不能直接只有一个查询,因为我们不能在DELETE上建立联接。

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

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

所以我决定使用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()));