2012-07-21 148 views
42

任何人都可以看到下面的查询有什么问题吗?mysql更新查询与子查询

当我运行它,我得到:

#1064 - 你在你的SQL语法错误;检查对应于你的MySQL服务器版本正确的语法手册使用 接近“一个地方a.CompetitionID = Competition.CompetitionID”在行8

Update Competition 
Set Competition.NumberOfTeams = 
(
SELECT count(*) as NumberOfTeams 
FROM PicksPoints 
where UserCompetitionID is not NULL 
group by CompetitionID 
) a 
where a.CompetitionID = Competition.CompetitionID 

回答

113

的主要问题是,内部查询不能与外部update语句中的where子句相关,因为在内部子查询甚至执行之前,where过滤器首先应用于正在更新的表。处理这种情况的典型方法是multi-table update

Update 
    Competition as C 
    inner join (
    select CompetitionId, count(*) as NumberOfTeams 
    from PicksPoints as p 
    where UserCompetitionID is not NULL 
    group by CompetitionID 
) as A on C.CompetitionID = A.CompetitionID 
set C.NumberOfTeams = A.NumberOfTeams 

演示:http://www.sqlfiddle.com/#!2/a74f3/1

+1

非常感谢你,这个技巧:)赞赏解释,欢呼! – user1542043 2012-07-21 01:29:04

+0

解释说这是一个非常好的答案。 – 2013-11-14 16:11:52

15

谢谢,我没有与INNER JOIN的UPDATE的想法。

在原始查询中,错误在于命名子查询,该子查询必须返回一个值,因此不能被别名化。

UPDATE Competition 
SET Competition.NumberOfTeams = 
(SELECT count(*) -- no column alias 
    FROM PicksPoints 
    WHERE UserCompetitionID is not NULL 
    -- put the join condition INSIDE the subquery : 
    AND CompetitionID = Competition.CompetitionID 
    group by CompetitionID 
) -- no table alias 

应该为每个竞争记录做窍门。

要注意:

的效果是不完全一样的mellamokb提出的查询,它不会与没有相应PickPoints更新比赛的记录。

由于SELECT id, COUNT(*) GROUP BY id只会计数ID的现有价值,

SELECT COUNT(*)总是会返回一个值,为0如果没有选择记录。

这可能会或可能不会成为您的问题。 mellamokb查询

0识别版本是:

Update Competition as C 
LEFT join (
    select CompetitionId, count(*) as NumberOfTeams 
    from PicksPoints as p 
    where UserCompetitionID is not NULL 
    group by CompetitionID 
) as A on C.CompetitionID = A.CompetitionID 
set C.NumberOfTeams = IFNULL(A.NumberOfTeams, 0) 

换句话说,如果没有相应的PickPoints发现,设置Competition.NumberOfTeams为零。

4

对于不耐烦:

UPDATE target AS t 
INNER JOIN (
    SELECT s.id, COUNT(*) AS count 
    FROM source_grouped AS s 
    -- WHERE s.custom_condition IS (true) 
    GROUP BY s.id 
) AS aggregate ON aggregate.id = target.id 
SET t.count = aggregate.count 

这是@mellamokb的回答,如上述,减少到了极致。