我有一个存储过程,我在WHERE
中使用字符串函数来传递多个参数值。
但是,如果我说
WHERE
cc.ClassCode IN (SELECT ClassCode
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
但如果我说:
,它会给我完全不同的错误结果WHERE
cc.ClassCode IN (SELECT *
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
在这两种情况下@ClassCode = '31439,68189,01239,41894...'
都是相同的值顺序,无论是SELECT ClassCode FROM
还是SELECT * FROM
背后的逻辑是什么?
完整查询:
ALTER PROCEDURE dbo.LossesByStateTest
@ClassCode nvarchar(max)
AS
BEGIN
SELECT
pc.Quoteid, pc.PolicyNumber, pc.AccidentDate,
cc.TransactionEffectiveDate, cc.ClassCode,
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY pc.QuoteID, pc.PolicyNumber, cc.AccidentDate ORDER BY (SELECT 0)) = 1
THEN pc.PaidLosses
ELSE 0
END as PaidLosses--,
FROM
tblLossesPlazaCommercialAuto pc
INNER JOIN
tblClassCodesPlazaCommercial cc ON pc.PolicyNumber = cc.PolicyNumber
AND pc.AccidentDate = cc.AccidentDate
AND cc.AccidentDate IS NOT NULL
--WHERE cc.ClassCode IN (SELECT ClassCode FROM [dbo].[StringOfStringsToTable](@ClassCode,',')) --Works fine
WHERE
cc.ClassCode IN (SELECT * FROM [dbo].[StringOfStringsToTable](@ClassCode, ',')) --- doesn't work
END
功能如下:
ALTER FUNCTION [dbo].[StringOfStringsToTable]
(@Strings varchar(8000),
@Separator char(1))
RETURNS @StringTable TABLE (String varchar(500))
AS
BEGIN
DECLARE @String varchar(500), @Pos int
SET @Strings = LTRIM(RTRIM(@Strings))+ @Separator
SET @Pos = CHARINDEX(@Separator, @Strings, 1)
WHILE @Pos > 0
BEGIN
SET @String = LTRIM(RTRIM(LEFT(@Strings, @Pos - 1)))
IF @String <> ''
INSERT INTO @StringTable VALUES (@String)
SET @Strings = RIGHT(@Strings, LEN(@Strings) - @Pos)
SET @Pos = CHARINDEX(@Separator, @Strings, 1)
END
RETURN
END
@scsimon我很抱歉。它没有用,因为我在SP中提供参数值的方式写在一列中,撇号在另一行。我在上面添加了一张图片。
Incorect方式:
查看最后一个撇号的位置?
这是正确的方法:
答案 0 :(得分:1)
你得到错误结果的原因是:
ClassCode
是因为您的返回表@StringTable
中没有列StringTable
。在您的函数中,您使用列String
声明了返回表RETURNS @StringTable TABLE (String varchar(500))
,如下所示:
WHERE
cc.ClassCode IN (SELECT String
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
WHERE
cc.ClassCode IN (SELECT *
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
因此,当您尝试上述语句时,您正在选择一个不存在的列。但是,这两个陈述应该产生相同的结果:
declare @table table (ClassCode varchar(16))
insert into @table (ClassCode) values
('31439'), --this is in @ClassCode
('01239'), --this is in @ClassCode
('41894'), --this is in @ClassCode
('00000'), --this is NOT in @ClassCode
('12345'), --this is NOT in @ClassCode
('somev') --this is NOT in @ClassCode
declare @ClassCode varchar (8000) = '31439,68189,01239,41894' --if this is NULL nothing is returned, which is what should happen
select * from @table where ClassCode in( select * from [StringOfStringsToTable] (@ClassCode,','))
select * from @table where ClassCode in (select String from [StringOfStringsToTable] (@ClassCode,','))
测试数据
.wrapper {
display: block;
position:fixed;
top: 0;
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 100px 0 20px;
}
.wrapper iframe {
height: 100%;
width: 100%;
}
答案 1 :(得分:0)
顺便说一句,我认为您也可以将where子句更改为
WHERE CHAINDEX(','+cc.ClassCode+',',','+@ClassCode+',')>0
答案 2 :(得分:0)
差异很大!
WHERE cc.ClassCode IN (SELECT *
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
如果您的TVL只有一个输出列,则此功能正常。如果你有更多的列,那么你的qry在后台重写为存在qry:
WHERE cc.ClassCode EXISTS (SELECT *
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
这个qry总是如此。或者为了更好地想象你可以重写它:
WHERE cc.ClassCode IN (SELECT cc.ClassCode
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
所以你必须指定一个输出列或使用条件:
WHERE cc.ClassCode IN (SELECT *
FROM [dbo].[StringOfStringsToTable](@ClassCode, ',') t
WHERE cc.ClassCode = t.ClassCode )
当您在IN
条件列中使用时,这是常见错误,该列不存在于子集中 - &gt;总是如此。
答案 3 :(得分:0)
在为使用Split字符串函数的Stored Procedure提供参数时,我应该更加小心。 由于我提供参数的方式,我得到错误结果的原因是:
EXEC SP_Name @ClassCode ='31439,
68189,67139,68528,68128
,33428,739889,5561
'
所以我不应该破坏提供的字符串。 这是正确的方法:
EXEC SP_Name @ClassCode ='31439,68189,67139,68528,68128,33428,739889,5561'