0

カウントテーブルがあり、複合キーフィールドの1つを名前変更するときにカウントを合計できるようにしたいと思います。これを説明するのは難しいので、SQLをいくつか紹介します。

表の例:

CREATE TABLE `test` (
  `id` int(11) NOT NULL,
  `type` int(11) NOT NULL,
  `count` int(11) NOT NULL,
  PRIMARY KEY (`id`,`type`)
);

いくつかのデータを挿入します。

INSERT INTO test VALUES(1, 10, 1);
INSERT INTO test VALUES(2, 20, 3);
INSERT INTO test VALUES(2, 10, 3);
INSERT INTO test VALUES(2, 30, 3);

データをクエリします。

mysql> SELECT SUM(count) as count FROM test WHERE id = 2;
+-------+
| count |
+-------+
|     9 |
+-------+

mysql> SELECT SUM(count) as count FROM test WHERE type = 10;
+-------+
| count |
+-------+
|     4 |
+-------+

非常にうまく機能し、高速で柔軟性があります。

ここで、タイプ10をタイプ20に再マップしたいと思います。

UPDATE test SET type = 20 WHERE type = 10;
Duplicate entry '2-20' for key 'PRIMARY'

ここでの使用ON DUPLICATE KEY UPDATEは無効です。クリエイティブなインサートで可能になると思いますが、よくわかりません。誰もがアプローチを考えることができますか?

4

3 に答える 3

1

クエリを更新すると、 id = 2andを使用して複数の行が作成されますが、これは制約type = 20のために許可されていません。primary key

代わりに、単一の列を主キーとして使用し、新しい行を挿入するときに自動インクリメントする必要があります。このようにして、一意であることが保証されます。

于 2012-08-02T15:26:46.300 に答える
1

1 つのアプローチは、PRIMARY KEY を「緩める」ことです。つまり、PRIMARY (一意の) KEY から一意でない KEY に変更します。これにより、重複する値が許可され、UPDATE ステートメントが成功し、(id,type) が一致する 2 つ (またはそれ以上) の行が作成されます。(これにより単一行の更新が問題になることに注意してください。そのため、一意の新しい列を追加することをお勧めします。そのためには AUTO_INCREMENT 列がうまく機能します。)


それをしたくない場合は、タイプ 10 行とタイプ 20 行のカウントを (ID ごとに) タイプ 20 行に「結合」し、タイプ 10 行のカウントを設定する方法もあります。ゼロに設定し、(オプションで) 別のステートメントで冗長なタイプ 10 行を削除します。

以下のステートメントは、最初の選択で 10 の値を 20 に「マッピング」することにより、タイプ 10 とタイプ 20 のカウントを「結合」します。


 -- combine count for types 10 and 20 as new count for type 20
 -- and set count to zero for type 10

 INSERT INTO test (id, `type`, `count`)
 SELECT t.id
      , IF(t.`type`=10,20,t.`type`) AS new_type
      , SUM(t.`count`) AS `count`
   FROM test t
  WHERE t.`type` IN (10,20)
  GROUP BY id, new_type
  UNION ALL
 SELECT u.id
      , u.`type`
      , 0 AS `count`
   FROM test u
  WHERE u.`type` = 10
     ON DUPLICATE KEY UPDATE `count` = VALUES(`count`);

 -- remove unnecessary type 10 rows.
 DELETE FROM test WHERE `type` = 10 AND `count` = 0;

注: 最初の SELECT の IF() 式は、次と同等です。

CASE WHEN t.type = 10 THEN 20 ELSE t.type END

2 番目の選択により、更新が必要なタイプ 10 の行がすべて取得されます。UNION ALL 演算子を使用して、これら 2 つの結果セットを連結します。

次に、結合 (連結) された結果セットを取得し、挿入に実行します。「重複」キーにヒットした任意の場所で、ON DUPLICATE KEY 句を介して更新アクションを実行します。

これをトランザクションで行い (InnoDB を使用している場合)、最初のステートメントが正常に完了したことを確認してから、DELETE. 最初のステートメントが例外をスローした場合 (不安定なトリガーがある可能性があります)、トランザクションを ROLLBACK する必要があります。また、何らかの理由で DELETE が失敗した場合にも ROLLBACK を実行する必要があります (おそらく、違反する外部キー制約があります)。

別の方法として、必ずしも DELETE を実行する必要はありません。タイプ 10 の行をカウント 0 のままにしておくこともできます。


重要:

これらのソリューションの両方を実装しないでください! それらのうちの1つだけ。

最初のアプローチは、データの変更を必要としないスキーマの変更です。その変更により、UPDATE が成功します。

2 番目のアプローチでは、スキーマが同じままである必要があり、(id,type) の UNIQUE KEY の存在 (および強制) に依存します。

于 2012-08-02T22:59:23.273 に答える
0

2 つの列に主キーを設定しましたが、更新後に 3 行目の主キーが 2 行目の主キーと同じになるため、これは許可されません。

最終的には 1..20; になります。2..20、2..20など

于 2012-08-02T15:27:42.990 に答える