То, как вы сформулировали запрос в настоящее время и ввод динамических списков параметров, подразумевает, что вы строите запрос в значительной степени в памяти и запускаете его, и в этом случае вам, вероятно, лучше всего использовать клиентский язык, который строит запрос, чтобы просто отбрасывать элементы, когда вы хотите их в любом случае. Вы не можете вставлять список напрямую через параметр или переменную SQL на любом диалекте, который я знаю, поэтому я бы не стал беспокоиться о многом, чтобы избежать чего-то, что вам в значительной степени нужно делать.
Это означает, что если вы хотите использовать более постоянную структуру запросов в том, как вы ее компилируете, - предположим, что у вас есть таблица CategoryBdocs с полем CategoryBdocID, объявленным как INT Identity (1,1), тогда вы можете получить что-то работает по линии текущего запроса, делая
select *
from library
where libraryID in
(select distinct libraryID from categoryAdocs where categoryAdocID in (4))
or LibraryID in
(select distinct libraryID from categoryBdocs where categoryBdocID in (-1))
и сцепить свой список категорий B после -1 - что всегда будет возвращать ничего, так что это безопасно. Если год не придет в виде списка вы могли бы получить, что работать в качестве необязательного параметра, используя что-то вроде
or Year in (COALESCE(2004, Year))
и, когда он вышел с NULL вместо 2004 было бы сопрягать с собой и вернуться.Однако вы не можете сделать это со списком, и я не могу придумать, как это сделать в SQL с дополнительным списком.
Все это основано на предположении, что вы строите запрос в памяти и выполняете его, хотя это то, что вы, кажется, делаете. Вы сказали, что вам не нравится это делать, и я согласен - это не идеально эффективно, и переход в список для конкатенации в запрос облегчает вам доступ к SQL Injection.
Чтобы обойти это, я бы предложил обернуть его в хранимую процедуру. Если вы затем передаете строки с разделителями, содержащие ваши идентификаторы для каждого из трех списков, вы можете разбить их на таблицы отдельных значений, присоединившись к таблице чисел/таблиц (подробности в другом из моих ответов - SQL select from data in query where this data is not already in the database?). Здесь вы можете написать его по линии
SELECT L.*
FROM Library L
INNER JOIN CategoryADocs A
ON L.LibraryID=A.LibraryID
INNER JOIN ([CategoryA Derived table]) ADocs
ON A.CategoryAdocID=ADocs.CategoryADocID
LEFT JOIN (SELECT B.* FROM CategoryBDocs B
INNER JOIN [CategoryB Derived Table] BDocs
ON B.CategoryBdocID=BDocs.CategoryBDocID) B
ON L.LibraryID=B.LibraryID
LEFT JOIN ([Years Derived table]) Y
ON L.Year=Y.Year
WHERE
COALESCE(B.LibraryID,-1)=CASE WHEN Len(@BIDs) > 1 THEN B.LibraryID ELSE -1
AND COALESCE(L.Year,-1)=CASE WHEN Len(@Years) > 1 THEN L.Year ELSE -1
Что я допускающими больше и сложнее, но позволяет поместить всю логику в SQL без необходимости каких-либо динамического построения запросов. Думаете ли вы, что это стоит того, что я оставлю вам?
есть ли также таблица категории Bdocs? – lexu
Простите, да, я просто схватил это выше, как пример того, где таблица categoryBDocs не была запрограммирована, потому что пользователь не выбрал из нее никаких параметров. Но да, вы правы, есть также таблица categoryBDocs. – 2010-04-06 11:13:00