Динамический запрос выбора с предложением where - PullRequest
2 голосов
/ 05 апреля 2019

У меня есть следующие образцы данных:

-- 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 Series, то нам нужно искать в A_Series Table, если значение B series, то поиск в таблице 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, как показано в запросе ожидаемого результата.

Ответы [ 2 ]

1 голос
/ 05 апреля 2019

Я считаю, что при выполнении динамического 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-> row может также работать. COALESCE () используется для построения поиска, а REPLACE () добавляет дополнительные одинарные кавычки.

0 голосов
/ 05 апреля 2019

Если вы на самом деле просто хотите получить результат вашего динамически созданного запроса, то также нет необходимости использовать динамический 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

Функция разделения строк

Это модифицированная версия функции Джеффа Модена :

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...