您目前对查询的表述方式和动态参数列表的输入对我来说意味着您在内存中大量构建查询并运行它,在这种情况下,您最好使用构建的客户端语言无论如何,当您需要元素时,查询就可以放入元素。在我知道的任何方言中,您都不能通过 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 中,而无需任何动态查询构建。您是否认为这值得复杂性,我会留给您!