为什么SELECT *和SELECT Column1之间的结果集不同?

时间:2016-11-22 23:58:08

标签: 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].[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方式:

enter image description here

查看最后一个撇号的位置?

这是正确的方法:

enter image description here

4 个答案:

答案 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'