查了一下,結果這是 MySQL 特有的問題。說是不能夠在變更資料時 select 同一個 table……
舉例來說,「將使用者 m 底下所有專案(Project)的『最後一個排程(Schedule)』刪除」。
以 HQL 來寫的話:
UPDATE Schedule s
SET s.status = :Delete
WHERE s IN (
SELECT MAX(s2) FROM Project p
LEFT JOIN p.schedules as s2
LEFT JOIN p.manager as m
WHERE m.id = :ID
AND s2 = (
SELECT MAX(schedules) FROM Project
WHERE id = p.id
)
)
以SQL來寫的話:
UPDATE Schedule s
SET s.status = :Delete
WHERE s.id IN(
SELECT s2.id FROM Project p
LEFT JOIN Schedule s2 ON s2.project_id = p.id
LEFT JOIN User m ON p.manager_id = m.id
WHERE m.id = :ID
AND s2.id = (
SELECT MAX(id) FROM Schedule WHERE project_id = p.id
)
)
像這樣就會出現錯誤訊息:
You can't specify target table 'Schedule' for update in FROM clause根據Stack Overflow的討論,看來是「insert」、「update」、「delete」都會遇到這種 BUG。
回到剛才的例子,若是要「將使用者 m 底下所有專案(Project)的『最後一個排程(Schedule)』刪除」,若是使用 Hibernate,最簡單的辦法就是先取得要刪除的 Schedule list ,如下所示:
org.hibernate.Session session;
List<Schedule> schedules = session.createQuery("SELECT MAX(s) FROM Project p" +
"LEFT JOIN Schedule s ON p.schedule_id = s.id " +
"LEFT JOIN User m ON p.manager_id = m.id " +
"WHERE m.id = :ID")
.setParameter("ID", 1234567890)
.list();
session.createQuery("UPDATE Schedule s " +
"SET s.status = :Delete " +
"WHERE s IN :List")
.setParameter("Delete", "DELETE")
.setParameterList("List", schedules)
.executeUpdate();
// 關閉 session
在「博客园」中,有個人提出一種比較複雜的解法,他的方法是將變成子集,然後 update。算是個挺麻煩又複雜的解法。有興趣可以點超連結自行觀看
沒有留言:
張貼留言