T-SQL奇怪的问题

时间:2011-08-12 21:42:17

标签: asp.net tsql

我有一个很大的T-SQL查询(我只在这里放了一部分,因为我非常确定其余部分工作正常):

 WHERE /*
                ******* missing filter *******
                this line should filter the risks by @LoggedInPersonID via role 
                ******************************
          AND */(@PropertyID IS NULL OR p.PropertyID = @PropertyID)
          AND (@PCodePattern IS NULL OR p.PCode LIKE @PCodePattern)
          AND (@ZipCodeIDS IS NULL 
                 OR p.ZipCodeID IN (@ZipCodeIDS))

你注意到@ZipCodeIDS是一个列表......好吧,我用代码填充了一些id。当@ZipCodeIDS包含一个SINGLE ID时,它可以正常工作,但如果我尝试发送多个ID(例如:“14,15”),它会给我错误....

你有任何线索吗?

Ps:当然我制作了@ZIpCodeIDS varchar因为我们在T-SQL中没有数组......

更新:如果我直接在查询中进行硬编码:IN (14,11)它完全有效......所以不知何故我没有正确地从我的代码中为多个值发送此参数我认为它不会看到“,”分离器...

UPDATE 2 :尝试拆分列表并将ID放入表中...当zipCodeIDS只有一个id时,查询就能完美运行。对于多个,不是......你在ELSE上看到了什么奇怪的东西吗?

    IF @ZipCodeIDS IS NOT NULL
BEGIN
    IF CHARINDEX(',', @ZipCodeIDS) = 0
    BEGIN
        insert @listofIDS values(@ZipCodeIDS)
    END
    ELSE
    BEGIN
        WHILE CHARINDEX(',', @ZipCodeIDS) != 0
        BEGIN
            insert @listofIDS values(Left(@ZipCodeIDS, PatIndex(',', @ZipCodeIDS) - 1))
            SET @ZipCodeIDS = SUBSTRING(@ZipCodeIDS, CHARINDEX(',',@ZipCodeIDS)+1, LEN(@ZipCodeIDS) - CHARINDEX(',',@ZipCodeIDS))
        END
    END
END

5 个答案:

答案 0 :(得分:3)

看一下这篇文章 -

http://www.sommarskog.se/arrays-in-sql.html

它讨论了许多可以改变查询的方法。

这个问题也可能有用 -

Parameterize an SQL IN clause

答案 1 :(得分:2)

你不能那样使用IN。在你的例子中,它试图寻找邮政编码等于'14,15'的p.ZipCodeID。

相反,您必须将p.ZipCodeID与比较所需的每个邮政编码,例如。

... OR p.ZipCodeID=14 OR p.ZipCodeID=15

替代方案(不太可取)是动态生成SQL语句,然后使用EXEC来运行它。当然,主要的问题是SQL注入。

答案 2 :(得分:1)

Declare @listofIDS table(zipcodeids varchar(10))

Declare @ZipCodeIDS varchar(100)
set  @ZipCodeIDS= '14,15'

set @ZipCodeIDS+= ','
;with cte as
(
select substring(@ZipCodeIDS, 1, charindex(',', @ZipCodeIDS) - 1) num, charindex(',', @ZipCodeIDS) pos
union all
select substring(@ZipCodeIDS, pos + 1, charindex(',', @ZipCodeIDS, pos +1) - pos - 1) num, charindex(',', @ZipCodeIDS, pos +1)
from cte
where charindex(',', @ZipCodeIDS, pos +1) > 0

)
INSERT @listofIDS 
select num from cte


.... or p.ZipCodeID in (select zipcodeids from @listofIDS) 

--------------------

试试这个(记得设置所有变量):

Declare @ZipCodeIDS varchar(100)
set  @ZipCodeIDS= '14,15'

set @ZipCodeIDS+= ','
;with cte as
(
select cast(substring(@ZipCodeIDS, 1, charindex(',', @ZipCodeIDS) - 1) as int) num, charindex(',', @ZipCodeIDS) pos
union all
select cast(substring(@ZipCodeIDS, pos + 1, charindex(',', @ZipCodeIDS, pos +1) - pos - 1) as int) num, charindex(',', @ZipCodeIDS, pos +1)
from cte
where charindex(',', @ZipCodeIDS, pos +1) > 0
)

SELECT /*... rest of your query that was not included in the question. no colon, nor anything else, just your query plus the small alteration i made in the end
...
...*/
WHERE /*
                ******* missing filter *******
                this line should filter the risks by @LoggedInPersonID via role 
                ******************************
          AND */(@PropertyID IS NULL OR p.PropertyID = @PropertyID)
          AND (@PCodePattern IS NULL OR p.PCode LIKE @PCodePattern)
          AND (@ZipCodeIDS IS NULL 
                 OR p.ZipCodeID IN (select num from cte))

答案 3 :(得分:0)

您可以DECLARE @ZipCodeIDS TABLE(id INT NOT NULL PRIMARY KEY)然后加入此表吗?

答案 4 :(得分:0)

 AND (@ZipCodeIDS IS NULL OR p.ZipCodeID IN (select z.ID from @ZipCodeIDS))

您声明SQL没有“数组”,但一切都在集合中运行。创建一个临时表或表变量,并用zipcodeID

填充它
declare @ZipCodeIDs = TABLE ( ID int NOT NULL)

用ints

填充@ZipCodeIDs

然后像以前一样使用你的代码

如果您尝试将数组从.net代码传递到数据库,则可以使用SQL Server 2008中的用户定义表类型执行此操作。