说我有这张桌子:
create table CodeTable (
CodeType int,
CodeVal char(2),
CodeDesc varchar(50))
insert CodeTable values
(1, 'AB', 'Desc for AB'),
(1, 'CD', 'Desc for CD'),
(1, 'DE', 'Desc for DE'),
(2, 'FG', 'Desc for FG'),
(2, 'HI', 'Desc for HI')
我希望存储过程从表中获取值,但是如果需要则排除指定的代码:
CREATE PROCEDURE [dbo].[GetCodes]
@CodeType int,
@NotInList varchar(100) = ''
AS
BEGIN
SET NOCOUNT ON;
declare @sql nvarchar(1000) = '
select CodeType, CodeVal, CodeDesc
from CodeTable
where CodeType = @CodeType'
if isnull(@NotInList, '') <> ''
set @sql += ' and CodeVal not in (@NotInList)'
exec sp_executesql @sql, N'@CodeType int, @NotInList varchar(100)', @CodeType, @NotInList
END
这些工作符合要求:
exec [dbo].[GetCodes] 1, ''
exec [dbo].[GetCodes] 1, 'AB'
但这些给了我所有代码:
exec [dbo].[GetCodes] 1, 'AB,CD'
exec [dbo].[GetCodes] 1, '''AB'',''CD'''
我错过了什么?我知道我可以使用sp_executesql
而不使用params来构建完整的SQL字符串,但我想知道我是否可以使用params。谢谢!
答案 0 :(得分:1)
传递给sp_executesql的参数被视为一个单独的值,而不是列表。所以当你传入AB,CD&#39;您的查询变为
select CodeType, CodeVal, CodeDesc from CodeTable where CodeType = 1 and CodeVal not in ( 'AB,CD' )
有关解决方法选项,请参阅以下问题的答案
答案 1 :(得分:1)
试试这个......这段聪明的代码消除了使用函数分割逗号分隔值的痛苦。但它的聪明和快速。
变量@NotInList
也是可选的,如果你传递一个值,它将被添加到实际的select子句中,否则它将被忽略。
CREATE PROCEDURE [dbo].[GetCodes]
@CodeType int,
@NotInList varchar(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
declare @xml xml,@SQL NVARCHAR(MAX);
set @xml = N'<root><r>' + replace(@NotInList,',','</r><r>') + '</r></root>'
SET @SQL = N'select CodeType, CodeVal, CodeDesc
from CodeTable
where CodeType = @CodeType '
+ CASE WHEN @NotInList IS NOT NULL THEN
N' AND CodeVal NOT IN (
select r.value(''.'',''varchar(max)'') as item
from @xml.nodes(''//root/r'') as records(r)
)' ELSE N'' END
exec sp_executesql @sql
, N'@CodeType int, @xml XML'
, @CodeType
, @Xml
END
答案 2 :(得分:0)
这是我在dynamic
项目列表中执行这些操作的一种方式。
我有一个表函数,它将采用一个连接的字符串,然后像我这样将它拆分成一个表。
FUNCTION [dbo].[SplitString] (@Value NVARCHAR(MAX), @SplitCharacter NVARCHAR(1), @AddWildCard BIT = 1)
RETURNS @Results TABLE
(
String NVARCHAR(MAX)
, Sequence INT
)
AS
BEGIN
DECLARE @Splitter NVARCHAR(MAX)
DECLARE @SplitPosition INT
DECLARE @SequenceNumber INT
SET @SequenceNumber = 1
-- PRINT 'ENTERING LOOP SPLITTER'
WHILE LEN(@Value) > 0
BEGIN
-- PRINT 'GETTING FIRST POSITION OF SPLITTER CHARACTER'
SET @SplitPosition = CHARINDEX(@SplitCharacter,@Value)
IF @SplitPosition = 0
BEGIN
SET @SplitPosition = LEN(@Value)
END
SET @Splitter = REPLACE(SUBSTRING(LTRIM(@Value),1,@SplitPosition),@SplitCharacter,'')
INSERT INTO @Results
SELECT
CASE
WHEN @AddWildCard = 1 THEN
'%' + RTRIM(LTRIM(@Splitter)) + '%'
ELSE
RTRIM(LTRIM(@Splitter))
END
, @SequenceNumber
SET
@Value = CASE
WHEN @SplitPosition > 0 THEN
SUBSTRING(@Value,(@SplitPosition + 1 ),LEN(@Value))
ELSE
''
END
SET
@SequenceNumber = @SequenceNumber + 1
END
-- PRINT 'RETURNING VALUE'
RETURN
END
所以,例如,如果我们有第一个场景:
exec [dbo].[GetCodes] 1, 'AB,CD'
我们将在where子句
中调用splitString函数然后使用上面代码的一些mod:
DECLARE @CodeType int
DECLARE @NotInList NVARCHAR(max)
SET @CodeType = 1
SET @NotInList = 'AB,CD'
declare @CodeTable table (
CodeType int,
CodeVal char(2),
CodeDesc varchar(50))
insert @CodeTable values
(1, 'AB', 'Desc for AB'),
(1, 'CD', 'Desc for CD'),
(1, 'DE', 'Desc for DE'),
(2, 'FG', 'Desc for FG'),
(2, 'HI', 'Desc for HI')
select CodeType, CodeVal, CodeDesc
from @CodeTable
where
CodeType = @CodeType
AND
(CASE WHEN LEN(ISNULL(@NotInList,0)) > 0 THEN
CASE WHEN CodeVal NOT IN (SELECT string FROM dbo.SplitString(@NotInList, ',',0)) THEN 1 ELSE 0 END
ELSE
1 END ) = 1
这样做意味着您不必运行sp_executesql