从UPDATE命令SQL引用外部派生表

时间:2012-05-27 11:32:51

标签: sql sql-update derived-table

我需要在UPDATE命令中从查询中引用cartProduct派生表。有人可以解释我,我做错了什么,我该如何解决它。

UPDATE memberships SET points = (points + COALESCE( 
    (SELECT pts 
    FROM (
        SELECT pid0, SUM (S) as Pts
        FROM ( 
            (SELECT pid0, SUM (pts1) as S
            FROM 
                (SELECT DISTINCT pid0, pid0,pts1
                FROM cartProduct
                WHERE pid0 = i1) as pointsForPath 
            GROUP BY pid0)) as allPtsTbl
        GROUP BY pid0) as temp 
    WHERE memberships.cid = 57010 AND memberships.pid = temp.pid0 ),
0))
FROM (
    SELECT t0.pid as pid0,t1.pid as pid1,t1.invitedby as i1,t1.points as pts1, t2.pid as pid2,t2.invitedby as i2,t2.points as pts2,t3.pid as pid3,t3.invitedby as i3, t3.points as pts3
    FROM memberships t0, memberships  t1, memberships  t2, memberships  t3
    WHERE t0.cid = t1.cid AND t1.cid = t2.cid AND t2.cid = t3.cid) as cartProduct;

这个查询必须做什么并不重要,这导致我想要优化的一小块复杂查询。我唯一的问题是如何从UPDATE子查询中引用cartProduct。 我想要优化的查询是由C代码生成的...正如您所看到的,我必须多次计算相同的内容。此查询只有3个派生表,但它也可以是100+,然后我必须等待超过10个小时来计算它。

UPDATE memberships SET points = points + COALESCE((
SELECT pts 
FROM (
    SELECT pid0, SUM (S) as Pts
    FROM ( 
        SELECT pid0, SUM (pts1) as S
        FROM 
            (SELECT DISTINCT pid0, pid1,pts1
            FROM (
                SELECT t0.pid as pid0, t1.pid as pid1, t1.invitedby as i1, t1.points as pts1 
                FROM memberships t0, memberships t1
                WHERE t0.cid = 57010 AND t1.cid = 57010) as paths
            WHERE pid0 = i1) as pointsForPath
        GROUP BY pid0
        UNION ALL
        SELECT pid0, SUM (pts2) as S
        FROM (
            SELECT DISTINCT pid0, pid2,pts2
            FROM (
                SELECT t0.pid as pid0, t1.pid as pid1, t1.invitedby as i1, t1.points as pts1 , t2.pid as pid2, t2.invitedby as i2, t2.points as pts2 
                FROM memberships t0, memberships t1, memberships t2
                WHERE t0.cid = 57010 AND t1.cid = 57010 AND t2.cid = 57010) as paths
            WHERE pid0 = i1 AND pid1 = i2) as pointsForPath
        GROUP BY pid0
        UNION ALL
        SELECT pid0, SUM (pts3) as S
        FROM (
            SELECT DISTINCT pid0, pid3,pts3
            FROM (
                SELECT t0.pid as pid0, t1.pid as pid1, t1.invitedby as i1, t1.points as pts1 , t2.pid as pid2, t2.invitedby as i2, t2.points as pts2 , t3.pid as pid3, t3.invitedby as i3, t3.points as pts3 
                FROM memberships t0, memberships t1, memberships t2, memberships t3
                WHERE t0.cid = 57010 AND t1.cid = 57010 AND t2.cid = 57010 AND t3.cid = 57010) as paths
            WHERE pid0 = i1 AND pid1 = i2 AND pid2 = i3) as pointsForPath
        GROUP BY pid0 ) as allPtsTbl
GROUP BY pid0) as temp WHERE memberships.cid = 57010 AND memberships.pid = temp.pid0 ),0)

抱歉我的英文不好,非常感谢。

1 个答案:

答案 0 :(得分:0)

如果性能问题,您可以尝试:

update memberships
    set points = points + coalesce(s.points, 0)
    from (nasty union all'ed subquery) s
    where memberships.id = s.id

(这假设您将pid0字段重命名为id。)

那就是说,你应该考虑以下几点:

  1. 了解正确的连接语法。在“where”子句中进行连接变得过时,就像在英语中使用“hath”或“thee”一样。通过选择特定值(您正在做什么)隐式地进行连接是非常危险的,因为您不知道从每个表中提取了多少记录,并且对查询的一个小改动可能会产生不利影响(例如选择两个用户)而不是一个)。
  2. 将讨厌的子查询放入临时表中。通常,我不提倡临时表,但这可能是优化器混淆的情况(在混合选择,删除和更新的查询中尤其如此)。
  3. 你为什么要在小组之前做一个明显的分享。首先,你可以做“总和(不同)”,虽然这几乎是不必要的。这表明您的联接存在问题。并且,错误的连接会导致查询无法完成。