HQL - 删除并出现 JOIN 错误

Posted

技术标签:

【中文标题】HQL - 删除并出现 JOIN 错误【英文标题】:HQL - Delete with JOIN error 【发布时间】:2016-07-21 16:26:00 【问题描述】:

我正在尝试使用 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 )",

EDIT 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

【问题讨论】:

如果您愿意,请考虑遵循以下简单的两步操作: 1. 如果您还没有这样做,请提供适当的 DDL(和/或 sqlfiddle),以便我们可以更轻松地复制问题。 2. 如果您尚未这样做,请提供与步骤 1 中提供的信息相对应的所需结果集。 谢谢你 StrawBerry。我无法创建 sqlfiddle,因为 HQL 给出了语法错误,甚至没有生成 SQL :( 我不明白那个评论。 Hibernate 无法执行 HQL,因为 HQL 查询中有“意外令牌”。但我认为查询看起来不错。 @scaisEdge 和考虑我正在尝试帮助我修复它。但是我还是有同样的问题 @MarcoNoronha 您能否将您的解决方案发布为您自己的答案并接受它?这将使投票更容易! 【参考方案1】:

为什么需要在要删除的同一张表上使用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 是另一个实体吗?这就是查询的意思。

【讨论】:

感谢您的回复。我不能直接这样做,因为我们不能在删除操作中加入。而且我们不能只有一个子查询,因为 mysql 有问题中解释的错误【参考方案2】:

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

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

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

我想出的最好办法是首先获取 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()

【讨论】:

我想这也可以。但我已经通过使用原生 SQL 解决了这个问题。【参考方案3】:

可能是因为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 在休眠状态下不起作用,请尝试使用 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);

【讨论】:

谢谢 scaisEdge 。列名是“id”。我想我没有理解你的建议。 很抱歉,这个建议的位置不对……我认为从 x 中选择 x 是问题……试试 chane column_name 具有有效的列名(或 *)。 ...我有正确的答案.. 我仍然不断收到 org.hibernate.hql.internal.ast.QuerySyntaxException:意外令牌:(在第 1 行附近,第 102 列 [DELETE FROM FinalGradeResult e WHERE e.id IN (SELECT id FROM (SELECT x.id FROM FinalGradeResult x 其中 x.student.id = :studentId AND x.classDiscipline.clazz.id = :clazzId ) as X )] 还有 scaisEdge,如果我使用“*”,错误会改变并指责 * 是意外标记。 我已建议您(从 x 中选择 x ... 可能是错误).. 对于我标记为 column_name 的第一个 x,您是什么意思i> .. 试着解释一下这部分查询的目标。【参考方案4】:

解决方案

在尝试了一切之后,我们得出了以下结论:

我们不能直接只有一个查询,因为我们不能在 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()));

【讨论】:

以上是关于HQL - 删除并出现 JOIN 错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 LEFT JOIN 删除

当具有相同术语的 HQL 选择有效时,为啥此 HQL 删除失败?

Hibernate 实体管理器 find() 仍然可以检索删除 hql 的实体

删除了未打包的 gems 文件夹,现在出现错误

即使在 HQL 查询中使用 Join Fetch,休眠延迟初始化异常

hibernateTemplate hql 批量更新 (删除添加修改)也类似