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 错误的主要内容,如果未能解决你的问题,请参考以下文章
当具有相同术语的 HQL 选择有效时,为啥此 HQL 删除失败?
Hibernate 实体管理器 find() 仍然可以检索删除 hql 的实体