2017-07-01 53 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$$ 

我猜理念的正確,我準備在字符串中使用%value%把它用在SQL命令進行過濾,並檢查後,如果該值不爲空,我想將它添加到WHERE子句。

回答

0

好吧,不是真的看到你的代碼做什麼,但你最可能尋找的是準備語句:你不能在存儲過程中連接sql,因爲這是編譯代碼,但是你可以連接一個字符串和地方在準備聲明中+執行該聲明。

短的例子:

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是一個說明性語言。你告訴服務器你想找什麼,而不是如何找到它。查詢優化器的任務是確定如何查找行。

簡單的解決辦法就是讓查詢優化照顧優化掉不必要的conditons,它會自動

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 

確實在編制查詢計劃,優化的任務是確定如何真正找到所需的行儘可能少的工作。

由於name是查詢執行期間無法更改的變量,因此優化程序會將其解析爲常量。由於name是一個常量,因此name IS NULL是一個常量表達式,可以在查詢執行開始之前將其解析爲true或false。

如果屬實,OR表達式始終爲真,因此不需要解析表達式CONCAT('%',name,'%'),因此可以對其進行優化。

如果爲false,則將表達式CONCAT('%',name,'%')解析爲常量,並將每一行與它進行比較。 CONCAT()不需要針對每一行進行處理,因爲這個值不會因行而改變,所以不需要事先做這件事。

因此,沒有必要重寫您的查詢。只需制定一個邏輯上有效的表達式,優化器將完成剩下的工作。

另外,字符排序默認情況下不區分大小寫,所以除非您更改了這個,否則不需要使用LOWER()

而且,如上所述,您之前將%連接到變量的塊也是不必要的,因爲只有當我們需要(當變量不爲空時)我們纔可以在WHERE中執行這些塊。