SQL незадължителни параметри чрез VB.net

Имам страница за търсене на документи с три списъчни кутии, които позволяват множество селекции. те са:

Категория А

година

Категория Б

Само категория А е задължителна, останалите са незадължителни параметри и може да са празни.

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

Постигнах това да работи чрез изграждането на динамичен SQL низ, но е объркано и мразя да го използвам, така че реших да попитам тук, ако някой може да види по-лесен начин за това. Следва пример за вид динамична SQL заявка, до която стигнах:

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

Допълнителни подробности:

Имам следните DB таблици, настроени:

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

CategoryADocs (таблица с връзки, тъй като всеки документ може да принадлежи към множество опции в категория A)

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

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

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

Споменавам „по-лесен“ начин да направя това, в идеалния случай търся най-добрия начин да направя това, би било страхотно, ако беше по-лесно от динамичното изграждане чрез SQL, но ако е по-ангажирано, няма проблем.


person Community    schedule 06.04.2010    source източник
comment
има ли и таблица categoryBdocs?   -  person lexu    schedule 06.04.2010
comment
Съжалявам, да, току-що взех тази по-горе като пример за това, че таблицата categoryBDocs не е била поискана, защото потребителят не е избрал никакви параметри от нея. Но да, прав си, има и таблица categoryBDocs.   -  person    schedule 06.04.2010


Отговори (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 инжектиране по-лесно.

За да заобиколите това, бих предложил да опаковате това в съхранена процедура. Ако след това подадете разделени низове, съдържащи вашите идентификатори за всеки от трите списъка, можете да ги разделите на таблици с индивидуални стойности, като се присъедините към таблица с числа / таблица (подробности в друг от моите отговори - 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, без да се нуждаете от динамично изграждане на заявки. Дали смятате, че си струва сложността, оставям на вас!

person eftpotrm    schedule 06.04.2010
comment
Отлично, благодаря, че отделихте време да напишете толкова задълбочен отговор, много ценя. Мисля, че ще опитам втората ви опция, опаковане в sproc, по-сложна е, но мисля, че е за предпочитане пред динамичното изграждане на заявката. - person ; 06.04.2010