SQL Server - 可选where子句 - 空表值参数

时间:2014-07-07 18:32:47

标签: sql-server sql-server-2008 tsql

我有三个TVP - A,B和C

A永远不会是空的。 B或C可以为空。

AND
SomeId IN (SELECT n FROM @A) -- First
AND
SomeId IN (SELECT n FROM @B) -- Second -- Make this optional
AND
SomeId IN (SELECT n FROM @C) -- Third -- Make this optional

我需要将Second / Third条件设为可选。我已经尝试了很多像case, (SELECT .. OR @B = null)这样的东西,但由于它们是表值参数,因此无效。

6 个答案:

答案 0 :(得分:1)

尝试使用OR

AND
(
SomeId IN (SELECT n FROM @A) -- First
OR
SomeId IN (SELECT n FROM @B) -- Second -- Make this optional
OR
SomeId IN (SELECT n FROM @C) -- Third -- Make this optional
)

答案 1 :(得分:1)

如果只有第二和第三个条件是可选的,那么试试这个

AND SomeId IN (SELECT n FROM @A) -- First

OR

(
    SomeId IN (SELECT n FROM @B) -- Second -- Make this optional
    OR
    SomeId IN (SELECT n FROM @C) -- Third -- Make this optional
)

答案 2 :(得分:1)

我已经看到并设置了存储过程,其中参数默认为NULL

@A int = NULL,
@B int = NULL,
@C int = NULL

后面的代码将加载参数,@ B和@C可能加载也可能不加载。

当你达到WHERE条款时,你就把

SomeId IN (SELECT n FROM @A)
AND (SomeID IN (SELECT n FROM @B) OR @B IS NULL)
AND (SomeID IN (SELECT n FROM @C) OR @C IS NULL)

注意语法;它不是@B = NULL,而是@B IS NULL

答案 3 :(得分:1)

SELECT m.*, a.N, b.N, c.N FROM MyTable m
INNER JOIN @A a
    ON a.N = m.SomeId
LEFT JOIN @B b
    ON b.N = m.SomeId
LEFT JOIN @C c
    ON c.N = m.SomeId

所以你试图获得与a匹配的所有记录,然后如果它们与b或c匹配,那么你可以用它们做点什么吗?

答案 4 :(得分:1)

尝试以下方法。它以与原始查询相同的查询开始,但对于两个"可选的" TVP它添加了一个UNION ALL来选择" SomeId"仅在该特定TVP中存在行时才会出现。这与使用TVP作为过滤器的意图一致,如果有行中的行,否则它不会过滤掉行。

DECLARE @Main TABLE (ID INT);
INSERT INTO @Main (ID) VALUES (55);
INSERT INTO @Main (ID) VALUES (999);

DECLARE @TestA TABLE (Col1 INT);
INSERT INTO @TestA (Col1) VALUES (55);
INSERT INTO @TestA (Col1) VALUES (67855);
DECLARE @TestB TABLE (Col1 INT);
--INSERT INTO @TestB (Col1) VALUES (565);

SELECT tmp.ID
FROM @Main tmp
WHERE tmp.ID IN (SELECT Col1 FROM @TestA)
AND tmp.ID IN (
               SELECT Col1 FROM @TestB
               UNION ALL
               SELECT tmp.ID
               WHERE NOT EXISTS(SELECT * FROM @TestB)
              )

查询(INSERT INTO @TestB已注释掉)返回55的值,因为@TestB是"可选"。但如果您取消注释INSERT INTO @TestB,则不会返回任何内容,因为@TestB不包含值55

答案 5 :(得分:1)

这样做会更加清晰,同样简洁:

;WITH AllowedIds_CTE (SomeId) AS (
    SELECT n from @A
    UNION
    SELECT n from @B
    UNION
    SELECT n from @C
)
SELECT * FROM SomeTable O
JOIN AllowedIds_CTE A
    ON O.SomeId = A.SomeId;

多个嵌套子查询和IN操作的可读性较差,并且与使用CTE /表连接的效率可能较低。

如果考虑到性能,则可以使用索引临时表替换此模型中的CTE(Common Table Expression),如果您知道UNIONUNION ALL可以替换为n 1}}值在@A@B@C之间是不同的。