首页 > 解决方案 > 想从表中选择,但它忽略了它

问题描述

我想要一个带有 ID 表参数的 select 语句。期望的行为是,如果表中没有元素,则获取所有值,但如果表中有元素,则仅选择那些值与表的 ID 参数匹配的值。

我的where条款如下所示:

SELECT * FROM BLAH
WHERE [TransactionDateTime] BETWEEN @BeginTransDate AND @EndTransDate AND
 ((SELECT COUNT(ID) FROM @LocationIds) = 0) OR (EXISTS (SELECT 1 FROM 
@LocationIds WHERE t.LocationId = ID))

但是,结果总是带回所有位置,即使 LocationIds 表包含一个值并且该 ID 仅匹配一个值。

我可以设置值,但它仍然会带回所有位置:

DECLARE @LocationIds TABLE
(
  ID int
)

INSERT INTO @LocationIds (ID)
VALUES (10227)

标签: sqlsql-servertsql

解决方案


就个人而言,我将其作为 2 个查询来执行,因为查询计划是针对何时有行@LocationIds并且可能有足够的差异以致该计划的重用不会对另一个有益,因此您得到:

IF (SELECT COUNT(*) FROM @LocationIds) = 0 BEGIN
    SELECT *
    FROM BLAH
    WHERE [TransactionDateTime] BETWEEN @BeginTransDate AND @EndTransDate;
END ELSE BEGIN
    SELECT *
    FROM BLAH B
    WHERE [TransactionDateTime] BETWEEN @BeginTransDate AND @EndTransDate
      AND EXISTS (SELECT 1
                  FROM @LocationIds L
                  WHERE B.LocationID = L.ID);
END

或者,您可以使用动态 SQL 来构建查询,具体取决于是否@LociationIDs需要 的值:

DECLARE @SQL nvarchar(MAX);

SET @SQL = N'SELECT *' + NCHAR(13) + NCHAR(10) +
           N'FROM BLAH B' + NCHAR(13) + NCHAR(10) +
           N'WHERE [TransactionDateTime] BETWEEN @BeginTransDate AND @EndTransDate' +
           CASE WHEN (SELECT COUNT(*) FROM @LocationIds) = 0 THEN ';'
                                                             ELSE NCHAR(13) + NCHAR(10) +
                                                                  N'  AND EXISTS (SELECT 1' + NCHAR(13) + NCHAR(10) +
                                                                  N'              FROM @LocationIds L' + NCHAR(13) + NCHAR(10) +
                                                                  N'              WHERE B.LocationID = L.ID);'
           END;

EXEC sp_executesql @SQL, N'@BeginTransDate date, @EndTransDate date', @BeginTransDate = @BeginTransDate, @EndTransDate = @EndTransDate;

注意我已经猜到@BeginTransDateand@EndTransDate是 a date,而不是 a datetime。如果它们是后者,那么该查询无论如何都不太可能按您的意愿工作,您最好使用以下逻辑:

WHERE TransactionDateTime >= @BeginTransDate
  AND TransactionDateTime < DATEADD(DAY, 1, @EndTransDate)

推荐阅读