2017-07-01 12 views
0

SQL節を動的に構築する必要がありますが、何らかの理由で私のソースコードがうまくいかない場合があります。動的節を持つMySQLストアドプロシージャ

誰かが私を助けることができますか?

create procedure sp_test(in iduser bigint, in name varchar(50), in company varchar(50), in city varchar(50), in profession varchar(50)) 
begin 
    if not(name is null) then 
     begin 
      set name = '%' + lower(name) + '%'; 
     end; 
    end if; 

    if not(company is null) then 
     begin 
      set company = '%' + lower(company) + '%'; 
     end; 
    end if; 

    if not(city is null) then 
     begin 
      set city = '%' + lower(city) + '%'; 
     end; 
    end if; 

    if not(profession is null) then 
     begin 
      set profession = '%' + lower(profession) + '%'; 
     end; 
    end if; 

    select 
      usr.id_user, 
      usr.ds_icon, 
      usr.nm_user, 
      usr.ds_slug, 
      usr.ds_title, 
      usr.nm_company 
     from 
      tbl_user usr 
      left join tbl_profession pro on (pro.id_profession = usr.id_profession) 
      left join tbl_resume res on (res.id_user = usr.id_user) 
     where 
      (usr.ds_activation is null) and 
      usr.id_user <> iduser and 
      usr.id_user not in (select id_friend from tbl_user_friend where id_user = iduser) and 
      usr.id_user not in (select id_user from tbl_user_friend where id_friend = iduser) and 
      usr.id_user not in (select id_friend from tbl_user_friend_not_suggest where id_user = iduser) and 
      case when not(name is null) then 
       lower (usr.nm_user) like lower(name) or 
      end 
      case when not(company is null) then 
       lower (usr.nm_company) like lower(company) or 
      end 
      case when not(profession is null) then 
       lower (pro.nm_profession) like lower(profession) or 
      end 
      case when not(city is null) then 
       lower (res.ds_city) like lower(city) or 
      end 
      1 = 1 
     order by 
      usr.nm_user 
     limit 
      0,20 
     ; 
end$$ 

私はその正しい考えを推測、私はSQLコマンドでそれを使用する%value%を使用してフィルタリングする文字列を準備し、検査後の値がnullでない場合、私は、WHERE句に追加します。

答えて

0

あなたのコードが何をしているのか分かりませんが、探しているのは準備されたステートメントです:コンパイルされたコードであるためストアドプロシージャのSQLを連結することはできませんが、 prepare文で+その文を実行します。

ショート例:

SET @sql = CONCAT('SELECT some_columns FROM table 
       WHERE a=b', 
       @your_generated_where_statement_parts); 
PREPARE stmt FROM @sql; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 
0

SQLは宣言型言語です。あなたはサーバに、を見つけるのではなく、を見つける方法を教えてください。。問合せオプティマイザには、行の検索方法が決まります。

簡単な解決策は、クエリオプティマイザは、それが自動的にクエリプランを準備するには

WHERE 
... AND 
(name IS NULL OR usr.nm_user LIKE CONCAT('%',name,'%') AND 
(company IS NULL OR usr.nm_company LIKE CONCAT('%',company,'%') AND 
... -- repeat for other variables 

をしている、不要なconditonsを離れて最適化の世話をさせることです、オプティマイザの仕事は、実際に見つける方法を決定することです可能な限り少ない作業で所望の行を選択する。

nameはクエリの実行中に変更できない変数なので、オプティマイザはそれを定数に解決します。 nameは定数なので、name IS NULLは、クエリの実行が開始される前に真または偽のいずれかに解決できる定数式です。

真の場合、ORの式は常に真であるため、式CONCAT('%',name,'%')を解決する必要はないため、これは最適化されています。

falseの場合、式CONCAT('%',name,'%')が定数に解決され、各行がそれと比較されます。 CONCAT()は行ごとに処理される必要はありません。値は行ごとに変更されないため、事前に行う必要はありません。

したがって、クエリを書き換える必要はありません。論理的に有効な式を定式化するだけで、オプティマイザは残りの処理を行います。

また、文字照合ではデフォルトで大文字と小文字が区別されますので、これを変更しない限り、LOWER()は不要です。

%を連結する先のブロックは、WHEREの場合にのみ行うことができます(変数がnullでない場合)。

関連する問題