0

私はテーブルを持っています:

Name     GroupID    etc...
ABC
ABC
DEF
DEF
DEF
KKK
LLL
III
III

PHP/MYSQL ミックスをこれに処理したいと思います。

Name     GroupID    etc...
ABC       1
ABC       1
DEF       2 
DEF       2
DEF       2
KKK       0
LLL       0
III       3 
III       3

すなわち。行に重複する Name を持つエントリが存在する場合 (正確に文字列が一致する場合)、その Name を持つすべてのエントリに GroupID が割り当てられます (自動的にインクリメントされます)。エントリが一意の名前の場合、GroupID に 0 が割り当てられます

私のテーブルには 250,000 のエントリがあります。これを達成するための最速の方法は何ですか? 作業コードは素晴らしいですが、高レベルのアルゴリズムは私を動かすのに十分です.

ありがとう!

4

1 に答える 1

1

これは簡単な PHP スクリプトで実行できますが、私はデータベースがそれを単独で処理できるようにするという考えが気に入っています。

巧妙なUPDATE結合を使用してこれを行うこともできますが、テストできないため、代わりに一時テーブルを使用します。Nameアイデアは、カウント > 1 を持つすべての値を選択し、それらに行番号を一時テーブルに割り当てることです。次に、更新結合を使用して、元のテーブルの GroupID を変更します。

SET @rownum=0;

CREATE TEMPORARY TABLE groupnums (groupid INT, Name VARCHAR(16), numgroups INT)
  SELECT
    @rownum := @rownum + 1 AS groupid, 
    Name,  
    COUNT(*) AS numgroups 
  FROM original_table 
  GROUP BY Name
  HAVING COUNT(*) > 1

UPDATE 
  original_table
  JOIN groupnums ON original_table.Name = groupnums.Name
SET original_table.GroupID = groupnums.groupid

次に、残りのものを0に設定します

UPDATE original_table SET GroupID='0' WHERE GroupID IS NULL

そして、一時テーブルを取り除きます。

DROP TABLE groupnums;

アップデート:

これを自分で簡単にテストしたところ、動作しますが、 の増分値を直接取得できないことがわかりましたgroupid。は@rownum各グループではなく行ごとに増分されるため、次のようなグループになり、その間にギャップがあります。

/* Sample results - groups work, but have gaps between GroupID */
Name     GroupID    etc...
ABC       1
ABC       1
DEF       3
DEF       3
DEF       3
KKK       0
LLL       0
III       6 
III       6

更新 2 私はこれを少し複雑にしました。

深く考えると、@rownumはまったく必要ありません。一時テーブルで自動インクリメント ID を使用するだけです。GroupIDこれにより、その間にギャップがなくてもインクリメンタルが生成されます。上記と同じUPDATEステートメントを使用して、これに対して結合します。

CREATE TEMPORARY TABLE groupnums (groupid INT NOT NULL AUTO_INCREMENT, Name VARCHAR(16), numgroups INT)
  SELECT 
    NULL AS groupid
    Name,
    COUNT(*) AS numgroups
  FROM original_table
  GROUP BY Name
  HAVING COUNT(*) > 1
于 2012-06-27T22:32:27.513 に答える