データベースの中で、指定した項目の文字個数をカウントしてを保存したいと考えています。
★テーブル名 TEST
★項目名 KOUMOKU1 , KOUMOKU2
例えば テーブル TEST にはデータが20個位入っていて
KOUMOKU1 に りんご という文字が入っているとします。
テーブル TEST には
KOUMOKU1 にりんごと書かれているデータが5個あります。
SQL命令を実行すると
KOUMOKU2 に 5 という数字が入ります。
これを1~20全てのデータに適応させて KOUMOKU2 に全て数字が入る形を作りたいと考えています。
SQL命令がわかるかたおりましたらよろしくお願いします。
※データベースはPhpMyAdminを使用しています。
【1】更新における制限事項
UPDATE TEST T1 SET KOUMOKU2 = (SELECT COUNT(*) FROM TEST T2 WHERE T2.KOUMOKU1 = T1.KOUMOKU1)
上記のように書けば「いけそうな気がする~~~♪」などと思うのですが、エラーになります。
UPDATEでは更新されるテーブル(TEST)と同じテーブルをサブクエリ内では指定できないため、
自身(今回であればTESTテーブル)の集計結果を、
自身(同じくTESTテーブル)に書き戻すという動作は一発ではそもそも無理なのです。
【2】対応策その1
以下のように処理を分ければ一応は望みの形になります。
(ステップ1)集計用テーブル(仮にTEST2とする)を空っぽにしておく。
DELETE * FROM TEST2
(ステップ2)集計する。
INSERT INTO TEST2 SELECT KOUMOKU1, COUNT(*) AS KOUMOKU2 FROM TEST GROUP BY KOUMOKU1
(ステップ3)集計結果を TEST に書き込む。
UPDATE TEST T1 SET KOUMOKU2 = (SELECT KOUMOKU2 FROM TEST2 T2 WHERE T2.KOUMOKU1 = T1.KOUMOKU1 LIMIT 1)
【3a】対応策その1の問題点:時差による誤差の発生
以下のような事が起こりえます。
(ステップ2)集計する。
↓
ステップ2に進むまでの僅かな時間に、
TESTテーブルから「りんご」と入ったレコードが1件消された。あるいは増えた。
(1件だけとは限らない。もっともっと多いかもしれない。)
↓
(ステップ3)集計結果を TEST に書き込む。
ステップ1で集計した時と、ステップ2で書き込むまでの僅かな時差により、
本来得たい結果とは違うものが書き込まれるという事態になってしまう訳ですが、
作っておられるシステムはオークション出品商品の管理が目標であり目的ですから、
この問題をはらんでいる事は大きな問題になりえると思われます。
(「一応は望みの形」と書いたのは、このような問題点を抱えているからです。)
【3b】対応策その1の問題点:複数アクセスによる誤差の発生
間違って集計ボタンを2回クリックしてしまった場合などは、
同じプログラムが2つ動くことになり、しかも、連携は行なっていませんから、
むちゃくちゃなデータが書き込まれたりする可能性があります。
対応としては、
テーブルにロックをかけるなどがありますが、そもそも「対応策その1」自体が、
今件への解決策とは言えず、ロックの話などしだすと話が長くなるだけなので説明は割愛。
【4】対応策その2
対応策というほどのものでもありませんが、
ただ単に、同種のものが何点あるかという事を知りたいだけであれば、
SELECT T1.KOUMOKU1, (SELECT COUNT(*) FROM TEST T2 WHERE T2.KOUMOKU1 = T1.KOUMOKU1) AS KOUMOKU2 FROM TEST T1
といったような具合に、照会をかける度に計算させて、
「照会時点での個数を得る」という形にするほうがよろしいかと思います。
UPDATE TEST AS TEST1 SET KOUMOKU2 = ( SELECT COUNT(1) FROM TEST AS TEST2 WHERE TEST2.KOUMOKU1 = TEST1.KOUMOKU1 )
こんな感じでSQL1発を期待していますか?
MySQLはUpdate, Deleteで自己相関サブクエリが使えない のでSQL1発では無理です。
PHPでグルグル回しながらセットしていくか、
MySQLだけで完結したいのであれば、
ストアドプロシージャを使うといいです。
あとはテンポラリテーブルを使ってSQL2発で実装するとかです。