使用存储过程简化if语句

时间:2015-06-08 05:02:06

标签: sql sql-server sql-server-2008

我有一个以下存储过程,我重复类似的代码。我所做的就是根据Sample id1,sampleid2和sample id3检查条件,以类似的方式进行。 'y'的值一直持续到大约10,所以这将是一个很大的'if'条件的陈述。我试图看看是否可以采用更好的解决方案。感谢。

@select = 'select * from tbl Sample......'
if(x = 1 and y=1)
set @where = 'where Sample.id1 >=1 and <=10' 
if(x = 1 and y=2)
set @where = 'where Sample.id1 >=11 and <=20' 
if(x=2 and y=1)
set @where = 'where Sample.id2 >=1 and <= 10'
if(x=2 and y=2)
set @where = 'where Sample.id2 >=11 and <=20'
if(x=3 and y=1)
set @where = 'where Sample.id3 >=1 and <=10'
if(x=3 and y=2)
set @where = 'where Sample.id3 >=11 and <=20' //increment goes on 
exec(@select+@where)

6 个答案:

答案 0 :(得分:3)

一般情况下,如果JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"); JMXConnector connector = JMXConnectorFactory.connect(url, null); connector.connect(); connection = connector.getMBeanServerConnection(); ObjectName name = new ObjectName(getObjectNameByBrokerName(brokerName)); brokerMBean = (BrokerViewMBean) MBeanServerInvocationHandler.newProxyInstance(connection, name, BrokerViewMBean.class, true); ObjectName[] objNames = brokerMBean.getQueues(); for (ObjectName objName : objNames) { QueueViewMBean queueMBean = (QueueViewMBean) MBeanServerInvocationHandler.newProxyInstance(connection, objName, QueueViewMBean.class, true); System.out.println(queueMBean.getName()); } 和筛选列x, y等的值之间没有简单的关联,那么您可以将where谓词移动到由x和y值键入的表中,然后将其用作查找以应用于您的PROC。假设id1, id2被大量使用,查找表可以永久化并在SPROC输入映射列上建立索引。

x,y

然后你的过程简化为:

CREATE TABLE dbo.WhereMappings
(
    x INT,
    y INT,
    Predicate NVARCHAR(MAX),
    CONSTRAINT PK_MyWhereMappings PRIMARY KEY(x, y)
)

INSERT INTO dbo.WhereMappings(x, y, Predicate) VALUES
(1, 1, 'Sample.id1 > 5 and Sample.id2 <= 10'),
(1, 2, 'Sample.id1 > 7 and Sample.id2 <= 15'),
(2, 1, 'Sample.id2 > 2 and Sample.id3 <= 18');

Re:这解决了什么

虽然这不一定降低了原始查询的复杂性,但它确实允许对映射的仅数据维护方法,例如,可以编写Admin UI屏幕来维护(并验证!think Sql Injection)谓词映射,而无需直接修改SPROC。

修改

编辑后,CREATE PROC MyProc(@x INT, @y INT) AS BEGIN DECLARE @sql NVARCHAR(MAX); DECLARE @predicate NVARCHAR(MAX); SELECT TOP 1 @predicate = Predicate FROM dbo.WhereMappings WHERE x = @x AND y = @y; -- TODO THROW if predicate not mapped SET @sql = CONCAT('SELECT * FROM Sample WHERE ', @predicate); EXECUTE(@sql); END; x, y谓词中使用的已过滤列和范围之间存在关联,即idx设置列,{{ 1}}设置范围。

在这种情况下,只需将x的值附加到y列名称存根,然后将x子句的值乘以id到{{ 1}};

答案 1 :(得分:1)

您可以这样做:

select 
   * 
from 
  tbl Sample
where
    (@x=1 and @y=1 and Sample.id1>=..and Sample.id1<=..) --(or you could use between)
    OR (@x=1 and @y=2 and Sample.id1>=..and Sample.id1<=..)
..

答案 2 :(得分:1)

set @select = 'select * from tbl Sample......'
set @where = 'where Sample.id'+convert(nvarchar(10),@x)+' >=....and <=...' 
exec(@select+@where)

答案 3 :(得分:0)

我建议使用另一个sql表,它将包含所有这些条件的信息,如下面的屏幕截图所示。

enter image description here

然后在你的SQL查询中使用join,例如。(假设上表的名称为限制

select * from tbl Sample smpl
inner join Limit lmt
on @x=lmt.x and @y=lmt.y and  
( 
    (@x=1 and smpl.id1 >= lmt.Min_limit and smpl.id1 <=lmt.Max_limit) or 
    (@x=2 and smpl.id2 >= lmt.Min_limit and smpl.id2 <=lmt.Max_limit) or 
    (@x=3 and smpl.id3 >= lmt.Min_limit and smpl.id3 <=lmt.Max_limit)
)

在此我尝试避免动态查询。

答案 4 :(得分:0)

我经常试图找到输入和输出之间的关系,在这种情况下我发现了这种方式:

SET @where = 'WHERE Sample.id{0} >= {1} + 1 and <= {1} + 10'
SET @where = REPLACE(@where, '{0}', CAST(x AS varchar(5)))
SET @where = REPLACE(@where, '{1}', CAST((y - 1) AS varchar(5)))

答案 5 :(得分:0)

我想你想要这样的东西:

SET @where = 'where Sample.id' + CAST(@x AS VARCHAR(10)) + ' between ' +
              CAST((@y - 1) * 10 + 1 AS VARCHAR(10)) + ' and ' + 
              CAST(@y * 10 AS VARCHAR(10))