SQL для возврата таблицы на основе строкового входа

Я - новое с T-SQL. Так, помогите мне записать sql.

У меня есть таблица Price (Столбец Code является основным столбцом):

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. Спасибо.

1
задан JYelton 4 August 2010 в 17:42
поделиться

2 ответа

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

Он очень эффективен, но имеет два ограничения:

  • Вы не можете использовать обычные параметры SQL в предложении IN, поэтому вам придется автоматически добавлять их к вашей SQL-строке, что в некоторых случаях может открыть SQL-инъекции.

  • Это не совсем тот формат ввода, который вы просили: вместо A2 A2 это 'A1', 'A2'.

В любом случае, удачи!

EDIT: Если вы действительно хотите использовать формат A1 A2, вы не можете использовать IN и вам придется разделить строку, а затем проверить, содержит ли она текущий [Цена].Код. Только учтите, что это будет гораздо менее эффективно, чем мой первый пример.

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

Вот источник для функции Split.

2
ответ дан 3 September 2019 в 00:07
поделиться

Как упомянул Алон, вам нужна функция или запрос, чтобы разделить значения на строки в таблице. Другой способ сделать это - таблица 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 вместо nvarchar. DataLength вернет количество байт в строке, которое будет в два раза больше, чем количество символов в целом для 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
0
ответ дан 3 September 2019 в 00:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: