【问题标题】:Creating SQL IN clause from delimited parameter从分隔参数创建 SQL IN 子句
【发布时间】:2012-08-04 15:25:36
【问题描述】:

我有一个参数,它有多个用分号分隔的项目。我需要在 IN 子句中使用这些项目。例如:

parItems = 'item1;;item2;;item3'

然后我需要像这样添加到 sql 中:

SELECT somestuff, morestuff FROM sometable WHERE item in (parItems)

有没有简单的方法来完成这项工作?

对不起。正如我之前所说,它将在 Reporting Services 上查看 MSSQL DB 而不是 Oracle ODBC

【问题讨论】:

  • 有没有办法在将 parItems 输入到 sql 语句之前先对其进行格式化?这样会更容易。
  • SSRS 支持多值参数(特别是在 IN 子句中)

标签: sql sql-server reporting-services parameter-passing


【解决方案1】:

只需解析您的字符串以将;; 替换为',',您就可以将其直接传递给IN ('...') 语句。

'item1;;item2;;item3' --> 'item1','item2','item3'

最简单的方法是在将字符串作为参数传递之前对其进行转换。

像这样:IN ('item1','item2','item3')

【讨论】:

  • 我最终使用了这个。我不敢相信我错过了明显的!谢谢
  • MS SQL 中 IN 子句的语法与 oracle 中的相同:where column_name IN ('value1','value2','value3','value4') 检查是否将其传递给报告服务需要您以不同的方式转义引号。
  • EplusL,如果参数中只有一项,它可以正常工作。就像(项目)中的 WHERE Column_name 一样。只要您添加多个带有或不带有引号的项目,它就不起作用。我不认为 SQL 只是将其视为一个字符串。
  • 这就是为什么你必须通过转义引号将它作为一个字符串传递,然后一旦传递,你就可以将它设置在你的 () 中
【解决方案2】:

你可以。但是你需要一些基础设施。

您需要在 SQL 中定义的集合类型。假设每一项不超过100字节

CREATE TYPE item_arr
    AS TABLE OF varchar2(100);

然后您需要一个函数来解析分号分隔的列表并返回此集合类型。我会使用 Tom Kyte 的变体 in_list function

create or replace function in_list( p_items in varchar2 )
  return item_arr
as
  l_string varchar2(32000) := p_items || ';';
  l_items  item_arr := item_arr();
  l_pos    number;
begin
  loop
     exit when l_string is null;
     l_pos := instr( l_string, ';' );
     l_items.extend;
     l_items(l_items.count) :=
                 ltrim( rtrim( substr( l_string, 1, l_pos-1 ) ) );
     l_string := substr( l_string, l_pos+1 );
  end loop;
  return l_items;
end;

然后,你就可以在你的 SQL 语句中使用这个函数了

SELECT somestuff, morestuff 
  FROM sometable 
 WHERE item in (SELECT column_value
                  FROM TABLE( in_list( parItems )))

【讨论】:

    【解决方案3】:

    这是另一个变体;类似于贾斯汀的回答,但对于 SQL Server:

    下面的函数将返回一个可以加入的表。

    CREATE FUNCTION listToTable (@list nvarchar(MAX))
       RETURNS @tbl TABLE (item varchar(50) NOT NULL) AS
    BEGIN
       DECLARE @pos        int,
               @nextpos    int,
               @valuelen   int
    
       SELECT @pos = 0, @nextpos = 1
    
       WHILE @nextpos > 0
       BEGIN
          SELECT @nextpos = charindex(';', @list, @pos + 1)
          SELECT @valuelen = CASE WHEN @nextpos > 0
                                  THEN @nextpos
                                  ELSE len(@list) + 1
                             END - @pos - 1
          INSERT @tbl (item)
             VALUES (convert(varchar, substring(@list, @pos + 1, @valuelen)))
          SELECT @pos = @nextpos
       END
       RETURN
    END
    
    SELECT somestuff, morestuff 
    FROM sometable a
    join listToTable('item1;item2;item3') b
    on a.columnA = b.item
    

    【讨论】:

      【解决方案4】:

      如果列表相对较短(即少于 4000 个字符),另一种方法是使用 INSTR 函数:

      SELECT somestuff, morestuff FROM sometable
      WHERE INSTR( ';;' || parItems || ';;'
                 , ';;' || item || ';;'
                 ) > 0;
      

      然而,这种方法的主要缺点是谓词没有选择性。然而,这并不总是一个问题,具体取决于数据量。

      【讨论】:

        【解决方案5】:
        Use AsG
        Go
        Drop FUNCTION AsG_inListesiOlustur
        Go
        CREATE FUNCTION AsG_inListesiOlustur (@pDegerListesi nvarchar(MAX), @pBossaVarsayilanDeger varchar(50))
           RETURNS @pNeticeTablo TABLE (Deger varchar(50) NOT NULL) AS
        BEGIN
           DECLARE @Pozisyon        int,
                   @sonrakiPozisyon    int,
                   @uzunluk   int
        
           SELECT @Pozisyon = 0, @sonrakiPozisyon = 1
           Select @pDegerListesi = LTRIM(RTRIM(@pDegerListesi))
           If LEN(@pDegerListesi) = 0
             Begin
             If LEN(@pBossaVarsayilanDeger) > 0 
               Begin
               INSERT @pNeticeTablo (Deger) VALUES (@pBossaVarsayilanDeger)
               End
             End Else
             Begin   
             WHILE @sonrakiPozisyon > 0
               BEGIN
               SELECT @sonrakiPozisyon = CharIndex(',', @pDegerListesi, @Pozisyon + 1)
               SELECT @uzunluk = CASE WHEN @sonrakiPozisyon > 0
                                      THEN @sonrakiPozisyon
                                      ELSE Len(@pDegerListesi) + 1
                                 END - @Pozisyon - 1
               INSERT @pNeticeTablo (Deger)
                  VALUES (Convert(varchar, SubString(@pDegerListesi, @Pozisyon + 1, @uzunluk)))
               SELECT @Pozisyon = @sonrakiPozisyon
               End
             End
           RETURN
        END
        Go
        
        Select * From  [AsG].[dbo].[AsG_inListesiOlustur]('1,4', '0')
        Go
        
        Select * From  [AsG].[dbo].[AsG_inListesiOlustur]('', '')
        Go
        

        【讨论】:

          猜你喜欢
          • 2010-09-25
          • 1970-01-01
          相关资源
          最近更新 更多