0

我有一个文档搜索页面,其中包含三个允许多项选择的列表框。他们是:

甲类

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(链接表,因为每个 doc 可以属于 categoryA 中的多个选项)

CategoryBDocs(链接表,因为每个文档可以属于 categoryB 中的多个选项)

CategoryA(Cat A 类别列表)

CategoryB(Cat B 类别列表)

我提到了这样做的“更简单”的方法,理想情况下我正在寻找这样做的最佳方法,如果它比通过 SQL 动态构建它更容易,那会很酷,但如果涉及更多,那没问题。

4

1 回答 1

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))

并在 -1 之后连接您的 B 类列表 - 这将始终不返回任何内容,因此很安全。如果 Year 没有作为列表出现,您可以使用类似的东西将其作为可选参数工作

or Year in (COALESCE(2004, Year))

当它出现 NULL 而不是 2004 时,它会与自身匹配并返回。但是,您不能使用列表来做到这一点,而且我想不出在 SQL 中使用可选列表来做到这一点的干净方法。

这一切都基于您在内存中构建查询并执行它的假设,尽管这就是您似乎正在做的事情。你说过你不喜欢这样做,我同意 - 它的效率并不理想,并且传入一个列表以连接到一个查询中,让你更容易接受 SQL 注入。

为了解决这个问题,我建议将其包装在存储过程中。如果然后传入包含三个列表中每一个的 ID 的分隔字符串,则可以通过加入数字/计数表将它们拆分为单个值的表(我的另一个答案中的详细信息 - SQL select from data in query where this data是不是已经在数据库中了?)。从这里您可以按照以下方式编写它

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 中,而无需任何动态查询构建。您是否认为这值得复杂性,我会留给您!

于 2010-04-06T11:40:36.577 回答