Вы не можете использовать IN
таким образом. Вы должны сказать:
WHERE (Strategy = 'Option1' AND Items IN ('Item1', 'Item2'))
OR (Strategy = 'Option2' AND Items IN ('Item1'))
Это связано с тем, что IN
для каждого столбца в отдельности означает «вернуть любые строки, в которых для стратегии задано любое значение (вариант 1 или вариант 2), а для элементов - любое значение (элемент 1 или элемент 2)». Вы не можете применить эти две концепции по отдельности и ожидать, что SQL Server будет знать, что Item2 применяется только к Option1.
Теперь еще один вариант - использовать табличный параметр. Таким образом, вы можете определить тип таблицы следующим образом в SQL Server:
CREATE TYPE dbo.Options AS TABLE
(
Strategy VARCHAR(32),
Items VARCHAR(32)
);
Заполните DataTable в C # выбранными параметрами, затем передайте его. Ваш запрос становится:
CREATE PROCEDURE dbo.whatever
@tvp dbo.Options READONLY
AS
BEGIN
SELECT d.* FROM tbData AS d
INNER JOIN @tvp AS t
ON d.Strategy = t.Strategy
AND d.Items = t.Items;
END
GO
РЕДАКТИРОВАТЬ добавив еще одну опцию.
Если вы можете передать набор опций в таблицу в виде строки с двумя разделителями, например,
@Options = 'Option1,Item1;Option1,Item2;Option2,Item1'
Тогда вы можете использовать табличную функцию, например,
CREATE FUNCTION dbo.SplitMultiStrings
(
@List VARCHAR(MAX),
@d1 CHAR(1),
@d2 CHAR(1)
)
RETURNS TABLE
AS
RETURN
(
SELECT x, y FROM
(
SELECT
x = i.i.value('(./x/text())[1]', 'varchar(32)'),
y = i.i.value('(./y/text())[1]', 'varchar(32)')
FROM (
SELECT [XML] = CONVERT(XML, '<i><x>'
+ REPLACE(REPLACE(@List, @d1, '</x><y>'),
@d2, '</y></i><i><x>') + '</y></i>')
) AS x CROSS APPLY [XML].nodes('i') AS i(i)
) AS y WHERE x IS NOT NULL AND y IS NOT NULL
);
GO
Итак, теперь вы можете сказать:
CREATE PROCEDURE dbo.whatever
@Options VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
SELECT d.*
FROM dbo.SplitMultiStrings(@List, ',', ';') AS o
INNER JOIN tbData AS d
ON o.x = d.Strategy AND o.y = d.Items;
END TRY
BEGIN CATCH
RAISERROR('You probably have a trailing ; or other formatting issue.', 11, 1);
END CATCH
END
GO
И затем вызвать хранимую процедуру следующим образом (передав эту строку через запятую / точку с запятой из вашего приложения):
EXEC dbo.whatever @Options = 'Option1,Item1;Option1,Item2;Option2,Item1';
Но я все еще думаю, что вариант TVP - это путь.