Sql server 为什么在SELECT*和SELECT Column1之间有不同的结果集?
我有一个存储过程,其中我在Sql server 为什么在SELECT*和SELECT Column1之间有不同的结果集?,sql-server,tsql,stored-procedures,reporting-services,Sql Server,Tsql,Stored Procedures,Reporting Services,我有一个存储过程,其中我在where中使用字符串函数来传递多个参数值。 但是为什么我说它很好用呢 WHERE cc.ClassCode IN (SELECT ClassCode FROM [dbo].[StringOfStringsToTable](@ClassCode, ',')) 但如果我说: WHERE cc.ClassCode IN (SELECT * FROM [dbo].[
where
中使用字符串函数来传递多个参数值。
但是为什么我说它很好用呢
WHERE
cc.ClassCode IN (SELECT ClassCode
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
但如果我说:
WHERE
cc.ClassCode IN (SELECT *
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
在这两种情况下@ClassCode='31439681890123941894…'
的值顺序相同,无论是其从
中选择ClassCode还是从
背后的逻辑是什么
完整查询:
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
ALTER函数[dbo]。[StringOfStringsToTable]
(@Strings varchar(8000),
@分离器(1))
返回@StringTable表(字符串varchar(500))
作为
开始
声明@String varchar(500),@Pos int
设置@Strings=LTRIM(RTRIM(@Strings))+@分隔符
设置@Pos=CHARINDEX(@Separator,@Strings,1)
而@Pos>0
开始
设置@String=LTRIM(RTRIM(左(@Strings,@Pos-1)))
如果@String“”
插入@StringTable值(@String)
设置@Strings=RIGHT(@Strings,LEN(@Strings)-@Pos)
设置@Pos=CHARINDEX(@Separator,@Strings,1)
结束
返回
结束
@西蒙,我很抱歉。它不起作用,因为我在SP中提供参数值的方式写在一列中,而撇号在另一行。我在上面加了一张照片。
直截了当的方式:
看到最后一个撇号在哪里了吗
这是正确的方法:
EXEC SP_Name @ClassCode ='31439,68189,67139,68528,68128,33428,739889,5561'
顺便说一句,我想你也可以把where子句改为
WHERE CHAINDEX(','+cc.ClassCode+',',','+@ClassCode+',')>0
您获得错误结果的原因如下:
WHERE
cc.ClassCode IN (SELECT ClassCode
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
是因为您的返回表中没有列ClassCode
,@StringTable
。在函数中,您声明了返回表StringTable
,列String
如下:
返回@StringTable表(stringvarchar(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,','))
差别很大
WHERE cc.ClassCode IN (SELECT *
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
当您的TVL中只有一个输出列时,这就起作用了。如果您有更多列,则您的qry将在后台重写为现有qry:
WHERE cc.ClassCode EXISTS (SELECT *
FROM [dbo].[StringOfStringsToTable](@ClassCode, ','))
这句话永远是真的。或者,为了更好地想象,您可以重写它:
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 )
当您在条件列中的中使用时,这是一个常见的错误,该列不在现有子集中-->始终为真。在向使用拆分字符串函数的存储过程提供参数时,我应该更加小心。 由于我提供参数的方式,导致结果不正确的原因:
EXEC SP_Name @ClassCode ='31439,
68189,67139,68528,68128
,33428,739889,5561
'
所以我不应该打断提供的字符串。
这是正确的方法:
EXEC SP_Name @ClassCode ='31439,68189,67139,68528,68128,33428,739889,5561'
我们能看到功能吗?补充。这个功能很久以前由专业人士制作,并被永远使用。谢天谢地,我实际上刚刚注意到,即使我传递了不同的参数,它也会给我相同的结果。因此我建议使用这些拆分器中的一个,并加入到结果中。这是一本经常被引用的好书,看看最后的@pos setter
CHARINDEX
,也许吧?不,不应该。在这种情况下你错了。但这是常见的错误,所以我可以原谅你:)。为什么是@deadsheep39谢谢你的解释。但老实说,如果我以的形式运行它,其中cc.ClassCode(从[dbo].[StringOfStringsToTable](@ClassCode,,)
它仍然会给我一些奇怪的结果。我想你必须定义怪异的@oleg。与给出的输入相比,您对输入的内容有何期待?如果我说cc.ClassCode在哪里(从tblClassCodesPlazaCommercial中选择不同的ClassCode)
我得到了超过500000条记录,其中有200多条记录。但是,如果我以:的形式运行cc.ClassCode(从[dbo].[StringOfStringsToTable](@ClassCode,,'))中选择*)
那么我只得到了439行,只有两个不同的ClassCode,可以输出null吗?如果可以为null,则必须添加mycl不为null的位置…否,因为函数不是使用设置为参数的默认null值创建的。我没有测试用例,但我认为在null输入上,TVL有null输出。测试为空不是问题,或者测试我以前的答案很容易。它告诉我t.ClassCode
列名“ClassCode”无效。
我缺少简单的东西吗?