2010-04-06 2 views
0

У меня есть страница поиска документов с тремя списками, которые допускают множественный выбор. Они:Необязательные параметры SQL через VB.net

Категория A

Год

Категория B

Только категория А является обязательным, другие необязательные параметры и может быть пустым.

Каждый документ может принадлежать множеству опций в категории A и множеству опций категории B, но каждый документ имеет только один год, связанный с ним.

Я вроде как работал, создавая динамическую строку SQL, но это беспорядочно, и я ненавижу использовать его, поэтому я подумал, что спрошу здесь, сможет ли кто-нибудь увидеть более простой способ сделать это. Примером подобного динамического запроса SQL я в конечном итоге с следующим образом:

select * 
from library 
where libraryID in 
(select distinct libraryID from categoryAdocs where categoryAdocID in (4)) 
or year in (2004) 

Дополнительные детали:

я следующие таблицы БД установить:

библиотека (которая содержит YEAR параметр)

CategoryADocs (ссылка таблица, потому что каждый документ может принадлежать несколько вариантов в Категорияа)

CategoryBDocs (ссылка таблица, потому что каждый документ может принадлежать несколько вариантов в categoryB)

Категорияа (список категорий Cat A)

CategoryB (список категорий Cat B)

я упомянуть 'проще' способ сделать это, в идеале я ищу лучший способ сделать это, было бы здорово, если бы было проще, чем динамически строить его через SQL, но если это более привлекательно, это не проблема.

+0

есть ли также таблица категории Bdocs? – lexu

+0

Простите, да, я просто схватил это выше, как пример того, где таблица categoryBDocs не была запрограммирована, потому что пользователь не выбрал из нее никаких параметров. Но да, вы правы, есть также таблица categoryBDocs. – 2010-04-06 11:13:00

ответ

1

То, как вы сформулировали запрос в настоящее время и ввод динамических списков параметров, подразумевает, что вы строите запрос в значительной степени в памяти и запускаете его, и в этом случае вам, вероятно, лучше всего использовать клиентский язык, который строит запрос, чтобы просто отбрасывать элементы, когда вы хотите их в любом случае. Вы не можете вставлять список напрямую через параметр или переменную 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 без необходимости каких-либо динамического построения запросов. Думаете ли вы, что это стоит того, что я оставлю вам?

+0

Отлично, спасибо, что нашли время, чтобы написать такой подробный ответ, очень ценимый. Я думаю, что я попробую ваш второй вариант, обернувшись в sproc, это будет сложнее, но я думаю, что предпочтительнее дуамальное построение запроса. – 2010-04-06 13:19:40

Смежные вопросы