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”无效。
我缺少简单的东西吗?