2010-06-17 114 views
0

我有一个名为“父母”的主表和一个名为“childs”的相关表有没有一种方法来优化此更新查询?

现在我运行一个查询主表来更新一些值与子表的总和像这样。

UPDATE master m SET 
    quantity1 = (SELECT SUM(quantity1) FROM childs c WHERE c.master_id = m.id), 
    quantity2 = (SELECT SUM(quantity2) FROM childs c WHERE c.master_id = m.id), 
    count = (SELECT COUNT(*) FROM childs c WHERE c.master_id = m.id) 
WHERE master_id = 666; 

它按预期工作,但不是一个好的风格,因为我基本上对同一个结果做出多个SELECT查询。有没有一种方法来优化? (第一,查询数据和存储的值不是一个选项

我尝试这样做:

UPDATE master m SET (quantity1, quantity2, count) = (
    SELECT SUM(quantity1), SUM(quantity2), COUNT(*) 
     FROM childs c WHERE c.master_id = m.id 
) WHERE master_id = 666; 

但不起作用

更新:这里是解决方案,这要归功于感到沉沦:

你可以做这样的事情:

UPDATE master m 
    INNER JOIN childs c ON m.master_id = c.master_id 
SET master.quantity1 = c.quantity1, 
    master.count = 1 

如果一次只有一个孩子记录。但是,如果您想在连接的表中使用像SUM()这样的组函数不起作用。要么你得到一个“无效使用组功能的”如果“按组”部分或离开一个GROUP BY c.master_id‘

-- This doesnt work :(
UPDATE master m 
    INNER JOIN childs c ON m.master_id = c.master_id 
SET master.quantity1 = SUM(c.quantity1), 
    master.count = COUNT(c.*) 
GROUP by c.master_id 

的解决方案“,如果您使用您的SQL语法错误’是使用一个子查询JOIN:

UPDATE master m 
    INNER JOIN 
    (
    SELECT master_id, 
      SUM(quantity1) as quantity1, 
      COUNT(*) as count 
    FROM  childs c 
    GROUP BY master_id 
) c 
    ON c.master_id = m.master_id 
SET m.quantity1 = c.quantity1, 
    m.count = c.count 
WHERE m.master_id = 666; 

但由于这从childtable拉每一行的开销可能比使用更多的子查询像原来的SQL更大,所以你应该在WHERE子句添加到连接的。表只能得到你需要的行

另一个有趣的方法就是这种语法,它与JOIN和WHERE子句的作用相同,但只有在您想更新具有相同值的所有行并且子查询仅返回一行时才应使用,因为子查询的结果会附加到结果并可以像任何列一样使用。

UPDATE master m, 
    (
     SELECT SUM(c.quantity1) as sum_of_quantity, 
     COUNT(*) as rowcount FROM child c WHERE c.master_id = 666 
    ) as c 
SET m.quantity1 = c.sum_of_quantity, 
    m.count = c.rowcount 
WHERE m.master_id = 666; 
+0

你尝试过更新之前做你的计数,并将其存储伊娜变量传递到您的更新? – 2010-06-17 11:22:39

+0

你有哪个错误?您的更新是正确的。 – ksogor 2010-06-17 11:31:25

+0

它看起来像你有几个应该在下面工作的答案,但只是想指出,这似乎是重复的列和重复的数据之间非常规范化的设计。 – 2010-06-17 13:55:50

回答

2

重写利芬的解决方案到MySQL:

UPDATE master m 
JOIN (
    SELECT master_id 
      , SUM(quantity1) as quantity1 
      , SUM(quantity2) as quantity2 
      , COUNT(*) as count 
    FROM childs c 
    GROUP BY 
      master_id 
) c 
ON c.master_id = m.master_id 
SET 
    m.quantity1 = c.quantity1 
    ,m.quantity2 = c.quantity2 
    ,m.count = c.count 
WHERE m.master_id = 666; 
+0

工程就像一个魅力,但(看看我的问题的更新)不要忘记添加一个where子句的子查询,或者你会从数据库拉数百万行只是为了加入一个记录;) – 2010-06-21 11:13:36

1

我不知道它是否允许在MySQL中,但SQL Server允许您在更新中使用select的结果。

UPDATE master m SET 
    quantity1 = c.quantity1 
    , quantity2 = c.quantity2 
    , count = c.count 
FROM master m 
     INNER JOIN (
     SELECT master_id 
       , quantity1 = SUM(quantity1) 
       , quantity2 = SUM(quantity2) 
       , count = COUNT(*) 
     FROM childs c 
     WHERE master_id = 666 
     GROUP BY 
       master_id 
    ) c ON c.master_id = m.master_id 
+0

+1,这正是我如何做 – 2010-06-17 11:58:31

+0

如果您从我的答案中复制/粘贴MySQL的正确语法,我会删除那一个。 – Wrikken 2010-06-17 12:03:36

+0

@Wrikken,如果您确定这不适用于MySQL,那么无论如何,OP应该接受您的答案。 – 2010-06-17 12:13:04

0

您可以将数据选择到临时表中,然后使用该数据进行更新。

如果你也想在同一个往返插入“新”的数据,看看INSERT INTO ... SELECT FROM ...对重复密钥更新...

如果你已经在做,如果插入的行不存在,那么这个例子就是多余的。

例如:

INSERT INTO master m (id, quantity1, quantity2, count) 
SELECT master_id, SUM(quantity1) q1, SUM(quantity2) q1, COUNT(*) c 
    FROM childs 
    GROUP BY master_id 
ON DUPLICATE KEY UPDATE 
    m.quantity1 = q1, 
    m.quantity2 = q2, 
    m.count = c 

注意!这是未经测试的代码,但我认为应该可以反向引用UPDATE中的选择结果。

语法参考:http://dev.mysql.com/doc/refman/5.0/en/insert.html

相关问题