简体   繁体   English

具有动态子句的MySQL存储过程,其中

[英]MySQL stored procedure with dynamic clause where

I need to construct a SQL clause dynamic, I saw some examples using only case when, but for some reason my source code does not work. 我需要构造一个动态的SQL子句,我看到一些仅使用case的示例,但是由于某些原因,我的源代码无法正常工作。

Someone can help me , please ? 有人可以帮我吗?

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$$

I guess the idea its correct, I prepare the strings to filter using %value% to use it on SQL command, and after check if the value not is null, I want to add it to WHERE clauses. 我想这个主意是正确的,我准备使用%value%进行过滤的字符串以在SQL命令上使用它,然后检查值是否不为null之后,我想将其添加到WHERE子句中。

Ok, not really seeing what your code does, but what you are most likely looking for is prepared statements: You can not concatenate a sql in a stored procedure since that is compiled code, however you can concatenate a string and place that in a prepare statement + execute that statement. 好的,不是真的看到代码的作用,而是最有可能寻找的是预处理语句:由于已编译代码,因此无法在存储过程中连接sql,但是可以将字符串连接并放置在prepare中语句+执行该语句。

Short example: 简短示例:

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;

SQL is a declarative language. SQL是一种声明性语言。 You tell the server what you want to find , rather than how to find it . 您告诉服务器要查找的内容 ,而不是如何查找它 The query optimizer is tasked with determining how to find the rows. 查询优化器的任务是确定如何查找行。

The simple solution is to let the query optimizer take care of optimizing away the unnecessary conditons, which it does automatically 一种简单的解决方案是让查询优化器负责优化不必要的条件,该条件会自动执行

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

In preparing the query plan, the optimizer's job is to determine how to actually find the desired rows with as little work as possible. 在准备查询计划时,优化器的工作是确定如何以尽可能少的工作实际找到所需的行。

Since name is a variable that can't change during query execution, the optimizer resolves it to a constant. 由于name是在查询执行期间不能更改的变量,因此优化程序将其解析为常量。 Since name is a constant, then name IS NULL is a constant expression that can be resolved to either true or false before query execution begins. 由于name是一个常量,因此name IS NULL是一个常量表达式,可以在查询开始执行之前将其解析为true或false。

If true, the OR expression is always true, so there's no need to resolve the expression CONCAT('%',name,'%') , so this is optimized away. 如果为true,则OR表达式始终为true,因此无需解析表达式CONCAT('%',name,'%') ,因此可以对其进行优化。

If false, then the expression CONCAT('%',name,'%') is resolved to a constant and each row is compared against it. 如果为false,则将表达式CONCAT('%',name,'%')解析为常量,并与该常量进行比较。 The CONCAT() doesn't need to be processed for each row, because again the value won't change from row to row, so doing this in advance isn't necessary. 不需要为每一行都处理CONCAT() ,因为该值也不会在每一行之间改变,因此不必事先这样做。

So, there's no need to rewrite your query. 因此,无需重写查询。 Just formulate an expression that is logically valid, and the optimizer will do the rest. 只需制定一个在逻辑上有效的表达式,优化器就会完成其余工作。

Also, character collation is case-insensitive by default, so unless you changed this, LOWER() is unnecessary. 另外,字符排序规则默认情况下不区分大小写,因此除非您进行了更改,否则LOWER()是不必要的。

And, as mentioned above, your earlier blocks to concatenate the % to the variables are also unnecessary, since we can do those in WHERE only if we need to (when the variables aren't null). 而且,如上所述,您也不需要使用前面的块将%连接到变量,因为只有在需要时(变量不为null时),我们才可以在WHERE进行操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM