0

「親」というマスターテーブルと「子」という関連テーブルがあります

次に、マスターテーブルに対してクエリを実行して、このように子テーブルの合計でいくつかの値を更新します。

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;

しかし、それは機能しません。

更新:これが解決策です、everbodyのおかげで:

あなたはこのようなことをすることができます:

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

一度に1つの子レコードしかない場合。ただし、結合されたテーブルでSUM()のようなグループ関数を使用したい場合は機能しません。「groupby」の部分を残すと「groupfunctionの無効な使用」が発生するか、「GROUPBYc.master_id」を使用するとSQL構文にエラーが発生します。

-- 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

解決策は、サブクエリで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;

ただし、これにより子テーブルからすべての行がプルされるため、元のSQLのように多くのサブクエリを使用するよりもオーバーヘッドが大きくなる可能性があります。したがって、必要な行のみを取得するには、結合されたテーブルにWHERE句を追加する必要があります。

もう1つの興味深いアプローチは、この構文です。これは、WHERE句を使用したJOINと同じですが、すべての行を同じ値で更新する場合にのみ使用する必要があり、サブクエリの結果は次のようになります。結果に追加され、他の列と同じように使用できます。

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;
4

3 に答える 3

2

Lievenのソリューションを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;
于 2010-06-17T12:02:40.807 に答える
1

MySQLで許可されているかどうかはわかりませんが、SQL Serverでは、選択の結果を更新で使用できます。

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
于 2010-06-17T11:26:49.497 に答える
0

データを一時テーブルに選択し、そのデータを使用して更新することができます。

同じラウンドトリップに「新しい」データも挿入する場合は、INSERT INTO ... SELECT FROM ... ON DUPLICATE KEYUPDATE..を調べてください。

行が存在しない場合にすでに挿入を行っている場合、この例では冗長になります。

例:

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

于 2010-06-17T11:36:47.030 に答える