#sql-server #tsql #sql-server-2008-r2
#sql-сервер #tsql #sql-server-2008-r2
Вопрос:
У меня есть следующий образец данных:
-- 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
как показано в запросе ожидаемого результата.
Комментарии:
1. Для пояснения, следуя ответу @iamdave, вы ищете фактические наборы результатов или просто сценарии для запросов?
Ответ №1:
Я обнаружил, что при выполнении динамического SQL цикл while лучше всего подходит для построения SQL. Вы можете легко разбить его на небольшие фрагменты.
НАПРИМЕР
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 amp; 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
Функция разделения строк
Это модифицированная версия функции Джеффа Модена:
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;
Комментарии:
1. @MAK Зачем вам нужен только скрипт? Что вы делаете с ним, когда он у вас есть?