0

我认为这应该很简单,但我一直遇到问题。我只想从位于日期范围之间的表中返回所有数据。但我希望日期范围是可选的。

ALTER PROCEDURE [dbo].[sp_ExistingPlacements_Get]
     @DateFrom  DATE = NULL,
     @DateTo    DATE = NULL
 AS
BEGIN
    SET NOCOUNT ON;
    SELECT *
    FROM tblExistingPlacements
    WHERE
      CreatedDT > COALESCE(NULLIF(@DateFrom, ''), @DateFrom)
      AND
      CreatedDT < COALESCE(NULLIF(@DateTo, GETDATE()), @DateTo)
END

因此,如果没有传入日期,我们将返回整个表。

如果仅通过了开始日期 (DateFrom),我们将返回行 > 开始日期以及截至当前日期的所有内容。

如果仅通过了结束日期 (DateTo),则返回所有行 < 结束日期

当然,如果两个日期都已通过,则返回这些日期之间的所有行。

我是否与 COALESCE 走错了路?

4

2 回答 2

7

Use ISNULL(@parameter) OR (--your condition--) instead of COALESCE:

BEGIN
    SET NOCOUNT ON;
    SELECT *
    FROM tblExistingPlacements
    WHERE
      ((@DateFrom IS NULL) OR CreatedDT > @DateFrom)
      AND
      ((@DateTo IS NULL) OR CreatedDT < @DateTo)
END

If parameter was not provided ISNULL return TRUE, so second part of OR won't matter.

于 2013-03-27T11:43:23.393 回答
3

不要这样做。SQL 必须创建一个适用于任何情况的执行计划。听起来很统一,最好有三个单独的查询:

ALTER PROCEDURE [dbo].[sp_ExistingPlacements_Get]
     @DateFrom  DATE = NULL,
     @DateTo    DATE = NULL
 AS
BEGIN
    SET NOCOUNT ON;
    IF (@DateFrom IS NULL and @DateTo IS NULL) 
       SELECT field, field, field
       FROM tblExistingPlacements
       WHERE CreatedDT < GETUTCDATE();
    ELSE IF (@DateFrom IS NULL)
       SELECT field, field, field
       FROM tblExistingPlacements
       WHERE CreatedDT < @dateTo;
    ELSE IF (@DateTo IS NULL)
       SELECT field, field, field
       FROM tblExistingPlacements
       WHERE CreatedDT BETWEEN @DateFrom AND GETUTCDATE();
    ELSE
       SELECT field, field, field
       FROM tblExistingPlacements
       WHERE CreatedDT BETWEEN @DateFrom AND @DateTo;
END

在没有指定参数的情况下返回整个表是否明智是非常值得怀疑的,但这不是重点。除了:

  • 从不*在查询中使用,始终明确指定投影列表
  • 始终在数据库中使用 UTC 时间

有关此主题的详细讨论,请参阅T-SQL 中的动态搜索条件

于 2013-03-27T12:12:59.507 回答