免責事項:これはテストされておらず、好奇心といくつかの遊びに端を発しています。「より安全な」ルートに進む代わりに使用する場合は、ご自身で判断してください。コメントは大歓迎です。誰かがもう少し遊んでみたい場合は、私が使用したsqlfiddleを次に示します。残りは頭から離れていましたが、夜遅くなので、間違いに反対票を投じないでください。
さて、好奇心から、更新をスピードアップする(ハックな)方法を見つけたと思います。この小さなテストを除いて、私はそれをテストしていません:
create table foo(id int, newid int);
insert into foo (id) values (1), (2), (3);
update foo, (select @prev:=0) vars
set foo.newid = @prev,
foo.id = if(@prev := id, id, id);
select * from foo
| ID | NEWID |
--------------
| 1 | 0 |
| 2 | 1 |
| 3 | 2 |
しかし、前の行からの情報が必要な select ステートメントで素晴らしい経験をしました。ユーザー変数を使用することで、(選択で) 自己結合テーブルを使用する必要がなくなります。読み込んでいるテーブルを同時に更新することはできないため、ダミーのテーブルが必要になります。私がこの回答を作成した理由をいくつか述べておきます。だからここにあります:
あなたの更新ステートメントは
SET @prev = 1; /*this is the value the row should have which has no previous year (or if countryID or industry changed)*/
SET @prevCountry = (SELECT countryID FROM MarketSizes ORDER BY `year`, countryID, industry, marketSizeID LIMIT 1);
SET @prevIndustry = (SELECT industry FROM MarketSizes ORDER BY `year`, countryID, industry, marketSizeID LIMIT 1);
/*also it's important to initialize the variable before-hand, not on the fly like in the example above. Otherwise MySQL complains about a syntax error, because it doesn't support an ORDER BY clause in a multi-table update statement. ORDER BY will be important in the statement!*/
UPDATE MarketSizes
SET growthRate = (annualSales - @prev) / @prev, /*here @prev holds the value of the previous row*/
/*and here come's your "where" clause. If country or industry change reset previousYear value to 1*/
marketSizeID = IF(@prevCountry != countryID OR @prevIndustry != industry, IF(@prev := 1, marketSizeID, marketSizeID), IF(@prev := 1, marketSizeID, marketSizeID)), /*why the convoluted IF()s? see explanation below, things got a bit messed up*/
marketSizeID = IF(@prev := annualSales, marketSizeID , marketSizeID), /*here the value of the current row gets assigned to @prev*/
/*Why the update on marketSizeID? And the IF(this,then,else)? That's the trick. Every other way to assign a new value to our variable @prev results in a syntax error. I just chose the primary key, because it's there. Actually it doesn't matter which column is used here and it might be another performance boost to choose a column which has no index on it (primary key has of course).*/
marketSizeID = IF(@prevCountry := countryID, marketSizeID, marketSizeID),
marketSizeID = IF(@prevIndustry := industry, marketSizeID, marketSizeID)
ORDER BY `year`, countryID, industry, marketSizeID;