4

stackoverflow で検索しましたが、私の質問に対する正確な答えが見つかりませんでした。できれば助けてください。

次のような SQL ステートメントを作成したい:

SELECT
  @tax1 := (complicated calculation formula),
  @owe := (another complicated calculation formula),
  IF(@owe=0, 0,@tax1/@owe)
FROM ...

ただし、ユーザー定義変数に関するMySQLのドキュメントでは、次のように言ってはいけません。

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

私の目標は、これらの非常に複雑な数式をコピーして貼り付けることを避けることです。これは読みやすさを妨げるためです。数式が変更されるたびに、すべての場所で変更されていることを確認する必要がありますが、そうすることでわかっています。大丈夫。

さらに、エイリアスは GROUP BY、HAVING、および ORDER 句でのみ機能するため、ALIASが機能しないこともわかっています。

他のいくつかの投稿を読み、最初にサブクエリを実行して @tax1 と @owe を最初に計算し、次に別のクエリを使用して結果を結合しました。しかし、これらの数式を単にコピーして貼り付けるよりもパフォーマンスが低下する可能性があると考えています。

誰かが彼らが何をするかについて何か提案はありますか? それとも、読みやすさとパフォーマンスのどちらかを選択することに行き詰まっていますか?

前もって感謝します。

4

2 に答える 2

2

はい、ユーザー変数を使用せずに SQL でこれを行う唯一の方法は、派生テーブルサブクエリを記述することです。次に、列エイリアスを使用して、これらの複雑な式の結果を参照できます。

SELECT tax1, owe, IF(owe=0, 0,tax1/owe) AS ratio
FROM (
  SELECT
    (complicated calculation formula) AS tax1,
    (another complicated calculation formula) AS owe
  FROM ...
) AS _sub

MySQL にはサブクエリの最適化にいくつかの問題がありますが、派生テーブルのケースは悪いケースの 1 つではありません。

MySQL とサブクエリに関する警告は、WHERE 句の範囲条件でサブクエリを使用することに関するものです。MySQL は、サブクエリが定数であることを認識できず、サブクエリが必要でない場合でも、サブクエリを依存サブクエリとして繰り返し再評価します。

于 2013-12-07T18:34:19.487 に答える
0

データの逐次評価、集計、グループ統計、および分類のために、select ステートメントで変数を定期的に使用します。

これは次の例です。

MySQL カテゴリごとに上位 X レコードのリストを作成し、すべてのレコードを以前の差異と組み合わせます

create table if not exists 
        closemovers engine=memory 
select 
          code 
        , date 
        , close 
        , rank 
        , prevclose 
        , sign 
        , cumm 
from 
        ( select 
                  `code` 
                , `date` 
                , `close` 
                , @rank := if( @code = code , @rank + 1 , 1) as rank 
                , @prevclose := if( @code = code , cast( @prclose as decimal(10,3) ), null) as prevclose 
                , if(@code = code, sign( @prclose - close), NULL) as sign 
                , @cumm := if(@code = code and @psign = sign(@prclose - close), @cumm + 1 , 1) as cumm
                , @psign := sign(@prclose - close) 
                , @code := code
                , @prclose := close 
        from 
            companyhistory 
        order by 
            code, date 
         ) as ranked 
 join 
        pricefeed 
                using (code) 
where 
        rank < 10 
        and sign is not null ;

これがヒントになれば幸いです

于 2013-12-07T18:17:04.340 に答える