Динамический, где предложение SQL цикла - PullRequest
0 голосов
/ 07 января 2019

Следующая хранимая процедура

  ALTER PROCEDURE [dbo].[get_data_Dyna]
    {
        @param1 varchar(max) = null,
        @param2 varchar(max) = null,    
        @start varchar(max) = null,
        @end varchar(max) = null
    }
    AS

    SELECT * from table where 
    (@param1 IS NULL OR column1 IN (SELECT data FROM dbo.delimited_list_to_table(@param1,',')))  
AND (@param2 IS NULL OR column2 IN (SELECT data FROM dbo.delimited_list_to_table(@param2,',')))
AND ....?????

Как это работает:

  • Все параметры могут быть разделены запятой
  • @ param1 значение может быть «Германия» или «Германия, США» или ноль. Это работает, как и ожидалось.
  • То же самое относится к @ param2

Я пытаюсь включить остальные параметры, которые должны работать следующим образом:

@ start = '0' и @ end = '100': в этом случае выражение будет выглядеть следующим образом

...AND val BETWEEN @start AND @end

@ start = '48, 60 'и @ end = '51, 99': в этом случае выражение будет выглядеть следующим образом

...AND ((val Between 48 and 51) or (val Between 60 and 99))

@ start = '48, 60,75 'и @ end = '51, 99,203': в этом случае выражение будет выглядеть следующим образом

...AND ((val Between 48 and 51) or (val Between 60 and 99) or (val Between 75 and 203))

Я не могу правильно включить выше 2/3 пункта. Я пытался записать его динамически, который работает для отдельных значений [Точка 1], но как написать точку 2/3?

Любая помощь очень ценится.

Ответы [ 3 ]

0 голосов
/ 07 января 2019

вот так. Комментарии / объяснения в запросе

-- create a sample table
declare @tbl table
(
    val int
)

-- put in some sample data
insert into @tbl 
values (48), (60), (51), (99), (75), (203)

-- these are the input parameter
declare @start  varchar(100),
        @end    varchar(100)

-- and these are the input value
select  @start  = '48,60,75',
    @end    = '51,99,203'

-- the actual query
; with 
start_end as
(
    -- here i am using [DelimitedSplit8K][1]
    select  s = s.Item, e = e.Item
    from    dbo.[DelimitedSplit8K](@start, ',') s
            inner join dbo.[DelimitedSplit8K](@end, ',') e
            on  s.ItemNumber    = e.ItemNumber
)
select  t.val
from    @tbl t
where   exists
(
        select  *
        from    start_end x
        where   t.val   between x.s and x.e
)

Вы можете получить его здесь DelimitedSplit8K

0 голосов
/ 07 января 2019

Пример ввода (Насколько мы понимаем, мы предполагаем ваши данные):

select 
* into ##demilit
from (
values 
 (1 ,'Ger','Ind',   100 )
,(2 ,'Ind',Null,    10  ) 
,(3 ,'Ger',Null,    24  )
,(4 ,'Ind','Ger',   54  )
,(5 ,'USA','Ind',   56  )
,(6 ,Null,'USA',    75  )-- NULL. But USA is three time came.
,(7 ,'USA','USA',   60  )-- same country with diff val.
,(8 ,'USA','USA',   80  )-- same country with diff val.
) demilit(Id,FromPr,ToPr,Val)

select * from ##demilit

ПРОЦЕДУРА (Вы просто используете это вместо ПРОЦЕДУРЫ):

create PROCEDURE [dbo].[get_data_Dyna]
(
    @param1 varchar(max) = null,
    @param2 varchar(max) = null,    
    @start varchar(max) = null,
    @end varchar(max) = null
)
AS
begin 
 select * from ##demilit d
 join (                                         --| Here We check the val btw @start and @end       
  select distinct s.FinalColumn StartVal        --|
  , e.FinalColumn EndVal                        --|
  from dbo.WithoutDelimit (@start,',') s        --| S means 'Start' 
  join (                                        --|
   select * from dbo.WithoutDelimit (@end,',')  --|
  ) e on s.id = e.id                            --| E means 'End'
 ) se                                           --| se mean StartEnd
 on d.val between se.StartVal and se.EndVal     --| Here YOUR CONDITION is accomplished 
 where (                                                    -- | checks whether 
  frompr in (                                               -- | column1 in @param1 or not
   select FinalColumn from dbo.WithoutDelimit (@param1,',') -- | frompr means, 'column1'
  ) or @param1 is null                                      -- |
 )
 and (                                                      -- | checks whether 
  ToPr in (                                                 -- | column2 in @param2 or not
   select FinalColumn from dbo.WithoutDelimit (@param2,',') -- | frompr means, 'column2'    
  ) or @param2 is null                                      -- |
 )
end

Звоните SP

[get_data_Dyna] null,'usa','75','100,' -- 6 row
[get_data_Dyna] 'Ind,Ger',null,'1,15','20,30' --2 and 3 rows are selected.
[get_data_Dyna] 'usa','usa','50,60','55,79' 
-- 7 and 8 has same country. But due to Val, 8 has been rejected.
[get_data_Dyna] NULL,'usa','70,60','80,79' 
-- 6 and 7 and 8 has been selected. Due to val condition.

Функция (Вызывается из SP):

alter function WithoutDelimit (     -- We use one Function for all conditions.
 @Parameter varchar (max)
 , @demilit varchar (1)
) 
returns @FinalTable table (
 Id int identity (1,1)              -- Auto increament
 , FinalColumn varchar (max)        -- It returns the values as a column.
) as
begin 

;with cte as                        -- recurrsive cte.
(
 select convert (varchar (255), @Parameter + @demilit) con
 , convert (varchar (255), @Parameter + @demilit) want
 union all
 select convert (varchar (255), stuff (con, 1, CHARINDEX (@demilit,con),'') )
 , substring (con, 1, CHARINDEX (@demilit,con)-1)
 from cte 
 where con <> ''
) insert into @FinalTable (FinalColumn)
select want  from cte
where con <> want

 return
end

Обратитесь к нам, если запрос требует обновления.

0 голосов
/ 07 января 2019

Хорошо, я думаю, что лучшим подходом здесь будет использование временных таблиц или табличных переменных. Пойдем с временными таблицами.

create table #StartEnd (start int not null, end int not null, primary key (start,end))

затем вставляем из него @start и @end, используя dbo.delimited_list_to_table . Теперь я не уверен в вашей реализации, поэтому предположу, что значения пронумерованы

insert into #StartEnd 
select starts.data, ends.data
  from dbo.delimited_list_to_table(@start,',') as starts
  join dbo.delimited_list_to_table(@end,',') as ends
    on starts.index = ends.index

Теперь мы должны отфильтровать значения. Два подхода. Условие присоединения или существования

...
join #StartEnd on val between start and end
...

and exists (select 1 from #StartEnd where val between start and end)

Надеюсь, это поможет

...