【问题标题】:What param type to use when I need to pass a list of IDs to be used for IN operator for a Stored Procedure?当我需要传递要用于存储过程的 IN 运算符的 ID 列表时,使用什么参数类型?
【发布时间】:2011-05-03 23:40:33
【问题描述】:

我想将 id '' 或 '1,2,3,4,5,6,7' 的列表传递给存储过程,然后在其中以下列方式使用:col IN (_PARAM)

我已经查看了SET,但它最多可以有 64 个元素。

当我定义存储过程时,我必须使用什么参数类型? 如果我有更多选择,其中一种与另一种相比有什么优势?

【问题讨论】:

    标签: sql mysql stored-procedures types


    【解决方案1】:

    为什么不使用 VARCHAR 将它们作为字符串传递。

    【讨论】:

    • 因为 IN 运算符需要像 IN ('1','2','3','4') 这样的单独条目传递,所以作为 varchar 传递失败。
    【解决方案2】:

    不是一个非常优雅的解决方案,但在 MySQL 成熟之前,您的选择是有限的。

    将逗号分隔的 id 拆分为标记并插入到内存表中。将内存表连接到您需要的任何其他表...

    完整的脚本在这里:http://pastie.org/1266830

    drop table if exists users;
    create table users
    (
    user_id int unsigned not null auto_increment primary key,
    username varbinary(32) unique not null
    )
    engine=innodb;
    
    insert into users (username) values ('a'),('b'),('c'),('d'),('e'),('f'),('g');
    
    drop procedure if exists foo;
    
    delimiter #
    
    create procedure foo
    (
    in p_id_csv varchar(1024)
    )
    proc_main:begin
    
    declare v_id varchar(10);
    declare v_done tinyint unsigned default 0;
    declare v_idx int unsigned default 1;
    
        if p_id_csv is null or length(p_id_csv) <= 0 then
            leave proc_main;
        end if;
    
        -- split the string into tokens and put into an in-memory table...
    
        create temporary table ids(id int unsigned not null)engine = memory;    
    
        while not v_done do
        set v_id = trim(substring(p_id_csv, v_idx, 
          if(locate(',', p_id_csv, v_idx) > 0, 
                    locate(',', p_id_csv, v_idx) - v_idx, length(p_id_csv))));
    
          if length(v_id) > 0 then
            set v_idx = v_idx + length(v_id) + 1;
                    insert into ids values(v_id);
          else
            set v_done = 1;
          end if;
      end while;
    
        select 
            u.* 
        from
         users u
        inner join ids on ids.id = u.user_id
        order by 
            u.username;
    
        drop temporary table if exists ids;
    
    end proc_main #
    
    delimiter ;
    
    call foo('2,4,6');
    

    【讨论】:

      【解决方案3】:

      其实经过一段时间的搜索,我找到了两个解决方案:

      一种方式

      使用 PREPARE 语句,这样我就可以在查询本身中将 CONCAT '1','2','3' 格式化为 VARCHAR 参数。

      所以应该是这样的

        SET @query= CONCAT('...WHERE col IN(',_PARAM,') ');
      

      第二种方式

      是将像 '1,2,3' 这样的连接列表作为VARCHAR 参数传递,并使用FIND_IN_SET 调用来查找值

      这样查询看起来像

      ... FIND_IN_SET(col,_PARAM)> 0
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-20
        • 1970-01-01
        • 2018-01-31
        • 2013-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多