SQL根据字符串输入返回表

时间:2010-06-02 03:45:54

标签: sql sql-server-2005 tsql

我是T-SQL的新手。所以,请帮我写一下sql。

我有桌子价格(代码栏是主要栏目):

Code    Value
A1       234
A2       525 
A3       566

我将输入一个字符串,而sql需要返回一个表。

Ex1:输入'A2' - >返回:

Code    Value
A2       525

Ex2:输入'A1 A3' - >返回:

Code    Value
A1       234
A3       566

Ex3:输入'A1 A3 A1' - >返回:

Code    Value
A1       234
A3       566

Ex4:输入'A1 A4' - >返回:

Code    Value
A1       234

请帮帮我。我正在使用SQL Server 2005.Tks。

2 个答案:

答案 0 :(得分:2)

SELECT [Price].Code, [Price].Value FROM [Price] WHERE [Price].Code IN ('A1', 'A2');

它非常有效,但它有两个限制:

  • 您不能在IN子句中使用常规SQL参数,因此您可以自动将其附加到SQL字符串,在某些情况下,可以打开SQL注入。

  • 这不完全是您要求的输入格式:而不是A2 A2它是'A1', 'A2'

祝你好运!

编辑:如果您真的想使用A1 A2格式,则无法使用IN并且您必须拆分字符串,然后检查它是否包含当前[Price].Code。请注意,它的效果远远低于我的第一个例子。

默认情况下,T-SQL不支持Split,因此您必须手动添加它:

CREATE FUNCTION [dbo].[Split]
(    
    @RowData NVARCHAR(MAX),
    @Delimeter NVARCHAR(MAX)
)
RETURNS @RtnValue TABLE 
(
    ID INT IDENTITY(1,1),
    Data NVARCHAR(MAX)
) 
AS
BEGIN 
    DECLARE @Iterator INT
    SET @Iterator = 1

    DECLARE @FoundIndex INT
    SET @FoundIndex = CHARINDEX(@Delimeter,@RowData)

    WHILE (@FoundIndex>0)
    BEGIN
        INSERT INTO @RtnValue (data)
        SELECT 
            Data = LTRIM(RTRIM(SUBSTRING(@RowData, 1, @FoundIndex - 1)))

        SET @RowData = SUBSTRING(@RowData,
                @FoundIndex + DATALENGTH(@Delimeter) / 2,
                LEN(@RowData))

        SET @Iterator = @Iterator + 1
        SET @FoundIndex = CHARINDEX(@Delimeter, @RowData)
    END

    INSERT INTO @RtnValue (Data)
    SELECT Data = LTRIM(RTRIM(@RowData))

    RETURN
END

然后,你可以这样做:

SELECT [Price].Code, [Price].Value FROM [Price] 
JOIN Split(@Codes, ' ') AS [Code] 
 ON [Code].Data = [Price].Code

Here's the source for the Split function

答案 1 :(得分:0)

正如Alon所提到的,您需要一个函数或查询来将值拆分为表中的行。另一种方法是使用Numbers表,该表可以是静态的,也可以作为公用表表达式的一部分创建:

Declare @Alist varchar(50);
Declare @Delimiter char(1);
Declare @DelimiterLength int;

Set @Delimiter = ' ';
Set @DelimiterLength = DataLength(@Delimiter);
Set @Alist = 'A1 A2 A3';
Set @Alist = @Delimiter + @Alist + @Delimiter;

With Numbers As
    (
    Select Row_Number() Over ( Order By C1.object_id ) As Value
    From sys.columns As C1
        Cross Join sys.columns As C2
    )
Select CharIndex(@Delimiter, @Alist, N.Value) + @DelimiterLength As Position            
    , Substring (
                @Alist
                , CharIndex(@Delimiter, @Alist, N.Value) + @DelimiterLength         
                , CharIndex(@Delimiter, @Alist, N.Value + 1)                            
                    - ( CharIndex(@Delimiter, @Alist, N.Value) + @DelimiterLength ) 
                ) As Value
From Numbers As N
Where N.Value Between 1 And ( Len(@Alist) - 1 )
    And Substring(@Alist, N.Value, @DelimiterLength) = @Delimiter
Order By N.Value

这里的空格分隔符存在一个小问题。 Len函数在其确定中忽略空格,因此我使用了DataLength函数,并确保将@Delimiter声明为varchar而不是nvarcharDataLength将返回字符串中的字节数,该字节数将是nvarchar的一般字符数的两倍。

Numbers CTE(或者它可以是一个静态表)只是一个连续整数的静态列表,对于像这样的情况非常有用。

这种方法也可以合并到一般查询中,您可以在其中分析另一个表中的每一行,如下所示:

With Numbers As
    (
    Select Row_Number() Over ( Order By C1.object_id ) As Value
    From sys.columns As C1
        Cross Join sys.columns As C2
    )
Select CharIndex(@Delimiter, A.List, N.Value) + @DelimiterLength            
    , Substring (
                A.List
                , CharIndex(@Delimiter, A.List, N.Value) + @DelimiterLength         
                , CharIndex(@Delimiter, A.List, N.Value + 1)                            
                    - ( CharIndex(@Delimiter, A.List, N.Value) + @DelimiterLength ) 
                )
From Numbers As N
    Cross Join ( Select A1.List From SomeTable ) As A
Where N.Value Between 1 And ( Len(A.List) - 1 )
    And Substring(A.List, N.Value, @DelimiterLength) = @Delimiter
Order By N.Value