【问题标题】:Dynamic select query with where clause带有 where 子句的动态选择查询
【发布时间】:2019-08-27 03:24:57
【问题描述】:

我有以下示例数据:

-- Table 1: A_Series

create table A_Series
(
    series varchar(10)
);
insert into A_Series values('A101'),('A102'),('A103'),('A104');  

-- Table 1: B_Series

create table B_Series
(
    series varchar(10)
);
insert into B_Series values('B101'),('B102'),('B103'),('B104'); 

现在我有了给定的输入值,可以根据传递的输入值在系列表中进行搜索。

例如:

DECLARE @input varchar(255) = 'A101,B102,A104'

我要生成SELECT语句如下图:

预期结果

select series 
from A_Series
where series in ('A101','A104')
union 
select series 
from B_Series
where series in ('B102')

上述预期结果的解释:如果给定的输入值是A系列那么我们需要在A_Series表中搜索,如果值是B系列那么 在B_Series 表中搜索WHERE 子句中的相关系列。

我的尝试

DECLARE @input varchar(255) = 'A101,B102,A104'
DECLARE @query varchar(max) = ''
DECLARE @Series_Where varchar(max) = ''

SET @query = ' SELECT STUFF((SELECT  '' SELECT * FROM [''+cast(name AS varchar(200))+''] UNION ALL '' AS [text()] FROM sys.tables t
                WHERE SUBSTRING(t.name,1,6) IN (SELECT SUBSTRING(Item,3,2)+''_SDR'' FROM udf_Split('''+@input+''','','')) 
                FOR XML PATH('''')
                ), 1, 1, '''')';

PRINT(@query);

无法创建WHERE,如预期结果查询所示。

【问题讨论】:

  • 为了澄清,按照@iamdave 的回答,您是在寻找实际的结果集,还是只是查询的脚本?

标签: sql-server tsql sql-server-2008-r2


【解决方案1】:

我发现在执行动态 SQL 时,while 循环最适合构建 SQL。 您可以轻松地将其分解为小块。

EG

    SET NOCOUNT ON;
DECLARE @input varchar(255) = 'A101,B102,A104'
DECLARE @InputT TABLE(Val varchar(255));
DECLARE @SQL VARCHAR(8000)='';
DECLARE @SQL_INNER VARCHAR(255)='';

INSERT @InputT SELECT VALUE FROM string_split(@input, ',');

DECLARE @i INT
DECLARE @search VARCHAR(255);
SET @i = ASCII('A');
WHILE @i <= ASCII('B') -- Set Max Table here'
BEGIN

    SELECT @search = COALESCE(@search + ', ', '') + Val FROM @InputT WHERE Val like CHAR(@i)+'%';

    SELECT @SQL_INNER = 'select series 
from ' + CHAR(@i) + '_Series
    where series in (''' + REPLACE(@search, ',', ''',''') + ''')'

    IF @i >  ASCII('A') SET @SQL += '
UNION ALL
'
    SET @SQL += @SQL_INNER;

    SET @i +=1;
    set @search = NULL;

END
PRINT @SQL

注意 - 我正在使用 String_Split() 加载我的表,但任何其他 csv->rows 方法也可以工作。 COALESCE() 用于构建 Search & REPLACE() 添加额外的单引号。

【讨论】:

    【解决方案2】:

    如果您实际上只想要动态创建的查询的结果,也无需使用动态 SQL:

    declare @A_Series table (series varchar(10));
    declare @B_Series table (series varchar(10));
    insert into @A_Series values('A101'),('A102'),('A103'),('A104');  
    insert into @B_Series values('B101'),('B102'),('B103'),('B104'); 
    
    declare @input varchar(255) = 'A101,B102,A104';
    
    with s as
    (
        select item
        from dbo.fn_StringSplit4k(@input,',',null) as s
    )
    select a.series
    from @A_Series as a
        join s
            on s.item = a.series
    union all
    select b.series
    from @b_Series as b
        join s
            on s.item = b.series;
    

    输出

    series
    A101
    A104
    B102
    

    字符串拆分函数

    这是Jeff Moden's function的修改版:

    CREATE function [dbo].[fn_StringSplit4k]
    (
         @str nvarchar(4000) = ' '              -- String to split.
        ,@delimiter as nvarchar(1) = ','        -- Delimiting value to split on.
        ,@num as int = null                     -- Which value to return.
    )
    returns table
    as
    return
                        -- Start tally table with 10 rows.
        with n(n)   as (select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1)
    
                        -- Select the same number of rows as characters in @str as incremental row numbers.
                        -- Cross joins increase exponentially to a max possible 10,000 rows to cover largest @str length.
            ,t(t)   as (select top (select len(isnull(@str,'')) a) row_number() over (order by (select null)) from n n1,n n2,n n3,n n4)
    
                        -- Return the position of every value that follows the specified delimiter.
            ,s(s)   as (select 1 union all select t+1 from t where substring(isnull(@str,''),t,1) = @delimiter)
    
                        -- Return the start and length of every value, to use in the SUBSTRING function.
                        -- ISNULL/NULLIF combo handles the last value where there is no delimiter at the end of the string.
            ,l(s,l) as (select s,isnull(nullif(charindex(@delimiter,isnull(@str,''),s),0)-s,4000) from s)
    
        select rn
              ,item
        from(select row_number() over(order by s) as rn
                    ,substring(@str,s,l) as item
            from l
            ) a
        where rn = @num
            or @num is null;
    

    【讨论】:

    • @MAK 为什么只需要脚本?拥有它后你会用它做什么?
    猜你喜欢
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 2013-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多