Я - новое с 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. Спасибо.
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
Как упомянул Алон, вам нужна функция или запрос, чтобы разделить значения на строки в таблице. Другой способ сделать это - таблица 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