Необязательные параметры SQL через VB.net - PullRequest
0 голосов
/ 06 апреля 2010

У меня есть страница поиска документов с тремя списками, которые позволяют несколько вариантов выбора. Они:

Категория А

год

Категория B

Обязательна только категория A. Остальные параметры являются необязательными и могут быть пустыми.

Каждый документ может принадлежать нескольким параметрам в категории 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 (таблица ссылок, поскольку каждый документ может принадлежать нескольким параметрам в категории A)

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

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

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

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

1 Ответ

1 голос
/ 06 апреля 2010

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

or Year in (COALESCE(2004, Year))

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

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

Чтобы обойти это, я бы предложил обернуть это в сохраненный процесс. Если затем вы передаете строки с разделителями, содержащие ваши идентификаторы для каждого из трех списков, вы можете разделить их на таблицы с отдельными значениями, объединив их с таблицей чисел / счетчиков (подробности в другом из моих ответов - Выбор SQL из данных в запросе где эти данные еще не в базе данных? ). Отсюда вы можете написать это в соответствии с

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 без необходимости динамического построения запросов. Если вы думаете, что это стоит сложности, я оставлю до вас!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...