6

私は、MySQL での変数宣言を含むクエリにかなり慣れていません。さまざまなスタイルを見てきましたが、これらが実際に何をするのか完全にはわかりません。これらが実際に何をするのかについて質問があります。

1)

set @row:=0;
SELECT name, @row:=@row + 1 AS rownum
FROM animal

2)

SELECT name, @row:=@row + 1 AS rownum
FROM (SELECT @row:= 0) c, animal

どちらも同じものを返します:

  name rownum
|| cat || 1 ||
|| cat || 2 ||
|| dog || 3 ||
|| dog || 4 ||
|| dog || 5 ||
|| ant || 6 ||

上記の 2 つのクエリの違いと、その範囲、効率、コーディングの習慣、ユースケースに関して、どちらを採用すべきか?

3)今、私がこれを行うと:

set @row:=0;
SELECT name, @row:=@row + 1 AS rownum
FROM (SELECT @row:= 123) c, animal

私は得る

  name  rownum
|| cat || 124 ||
|| cat || 125 ||
|| dog || 126 ||
|| dog || 127 ||
|| dog || 128 ||
|| ant || 129 ||

したがって、内部変数の初期化が外部初期化をオーバーライドし、後者を冗長のままにしているという意味ではありません(したがって、常にSELECT?

4)私が単に行う場合:

SELECT name, @row:=@row + 1 AS rownum
FROM animal

私は得る

   name  rownum
|| cat || NULL ||
|| cat || NULL ||
|| dog || NULL ||
|| dog || NULL ||
|| dog || NULL ||
|| ant || NULL ||

初期化されていないので理解できrowます。しかし、他のクエリを実行すると (変数rowが初期化されている可能性がありますか?) row、上記のクエリを実行するたびに変数がインクリメントされていることがわかります。つまり、最初の実行で結果が得られます。

  name rownum
|| cat || 1 ||
|| cat || 2 ||
|| dog || 3 ||
|| dog || 4 ||
|| dog || 5 ||
|| ant || 6 ||

そして、再実行すると、

  name rownum
|| cat || 7  ||
|| cat || 8  ||
|| dog || 9  ||
|| dog || 10 ||
|| dog || 11 ||
|| ant || 12 ||

それでrow、どこかに保管されていますか?そして、その範囲と寿命は?

5) 次のようなクエリがある場合:

SELECT (CASE WHEN @name <> name THEN @row:=1 ELSE @row:=@row + 1 END) AS rownum, 
       @name:=name AS name
FROM animal

これにより、常に正しい結果が得られます。

rownum  name
|| 1 || cat ||
|| 2 || cat ||
|| 1 || dog ||
|| 2 || dog ||
|| 3 || dog ||
|| 1 || ant ||

SELECTつまり、変数を先頭またはクエリに応じて初期化する必要があるとは限らないということではないでしょうか?

4

1 に答える 1

11

ユーザー変数に関するマニュアルのセクションを必ずお読みください。

上記の 2 つのクエリの違いと、その範囲、効率、コーディングの習慣、ユースケースに関して、どちらを採用すべきか?

クエリ 1) は複数のステートメントを使用します。したがって、これらのステートメントが実行される順序に依存し、変数がインクリメントされる前に確実に設定されます。
一方、クエリ 2) は、ネストされたサブクエリで初期化を行います。これにより、すべてが 1 つのクエリに変わります。初期化を忘れるリスクはありません。しかし、コードは mysql サーバーの内部動作、特に外側のクエリの結果の計算を開始する前にサブクエリを実行するという事実に大きく依存しています。

したがって、内部変数の初期化が外部初期化をオーバーライドし、後者を冗長のままにしているという意味ではありません(したがって、常にSELECT?

これは内部と外部に関するものではなく、順序に関するものです。サブクエリは の後に実行されるSETため、単に古い値を上書きします。

行はどこかに保存されていますか?そして、その範囲と寿命は?

ユーザー変数は、サーバー接続に対してローカルです。したがって、他のプロセスは設定の影響を受けません。同じプロセスでも、ユーザー変数の独立した設定により、複数の接続を維持する場合があります。接続が閉じられると、すべての変数設定が失われます。

クエリによっては、先頭または SELECT で変数を初期化する必要があるとは限らないということではないでしょうか。

マニュアルからの引用:

初期化されていない変数を参照すると、その変数の値NULLと型は文字列になります。

NULLそのため、変数を初期化する前に使用できますが、結果の値を適切な方法で実際に処理できるように注意する必要があります。ただし、クエリ 5) には、マニュアルに明示的に記載されている別の問題があることに注意してください。

原則として、ユーザー変数に値を割り当てたり、同じステートメント内で値を読み取ったりしないでください。期待どおりの結果が得られる可能性がありますが、これは保証されません。ユーザー変数を含む式の評価順序は定義されておらず、特定のステートメント内に含まれる要素に基づいて変わる場合があります。さらに、この順序は、MySQL サーバーのリリース間で同じであるとは限りません。では、MySQL が最初に評価され、次に代入が行われるSELECT @a, @a:=@a+1, ...と考えるかもしれません。@aただし、ステートメントを変更すると (たとえば、GROUP BYHAVING、またはORDER BY句を追加して)、MySQL が異なる評価順序で実行計画を選択する場合があります。

したがって、あなたの場合、チェックの@name:=name前にパーツが実行され、すべての値が同じになる可能性があります。そのため、現在は機能していても、将来も機能するという保証はありません。@name <> namerownum

この方法でユーザー変数を使用することについて、私は非常に懐疑的だったことに注意してください。いくつかの回答へのコメントで、マニュアルから上記の警告をすでに引用しました。また、ユーザー変数を使用して行に番号を付ける場合の保証についてのような質問もしました。他のユーザーはより実用的であるため、意図したとおりに機能し続けるという明示的な保証なしに機能するように見えるコードを使用することをいとわない.

于 2012-11-08T23:18:53.470 に答える