动态where子句sql循环

时间:2019-01-07 08:04:14

标签: sql-server stored-procedures where-clause

以下是存储过程

  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的值可以为“ Germany”或“ Germany,USA”或为null。一切正常。
  • @ param2也一样

我正在尝试包括其余有望按如下方式工作的参数:

@ start ='0'和@ end ='100':在这种情况下,where子句看起来像这样

...AND val BETWEEN @start AND @end

@ start = '48,60'和@ end = '51,99':在这种情况下,where子句看起来像这样

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

@ start = '48,60,75'和@ end = '51,99,203':在这种情况下,where子句看起来像这样

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

我无法正确包含上述第二/第三点。我试图动态地编写它,它适用于单个值[点1],但是如何编写点2/3?

非常感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

好吧,我认为最好的方法是使用临时表或表变量。 让我们来看一下临时表。

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

然后我们使用 dbo.delimited_list_to_table 从@start和@end插入其中。现在,我不确定您是否会执行该操作,因此我将假定值已编号

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)

希望这会有所帮助

答案 1 :(得分:0)

你去了。评论/解释都在查询中

-- 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

答案 2 :(得分:0)

样本输入(根据我们的理解,我们猜测您的数据):

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

如果查询需要更新,请回复我们。