动态SQL查询在比较日期时返回意外结果

时间:2011-12-23 16:02:56

标签: sql sql-server stored-procedures dynamic-queries

我正在构建一个动态查询作为SQL Server 2008中的存储过程,当我比较日期(作为参数提供)和日期时间(存储在数据库中)时,我得到了一些意想不到的结果。我搜索了一些比较两者的方法,没有考虑时间部分,发现了这个:

DATEDIFF(day, @d, v.ScheduledDate) = 0

我正在做的是尝试查找提供的日期参数和存储的ScheduledDate相同的记录(以天为单位,例如02/05/2011和 02/05/2011 11:26:19.157)。这是我写的这样做的查询:

SET @sql = 'SELECT e.Id, e.FirstName, e.LastName, v.ScheduledDate
            FROM Employee e, Visit v
            WHERE 1=1'
-- Several IF IS NOT NULL statements here

IF @d IS NOT NULL
BEGIN
  SET @sql = @sql + ' AND DATEDIFF(day, ''' + @d + ''',' + 'v.ScheduledDate) = 0
  AND v.EmpId = e.Id '
END
EXEC (@sql)

我希望此查询会导致当天安排访问的所有员工的所有ScheduledDates。换句话说,如果我有2名员工,分别是5和7,并且在2011年5月5日的访问表中有两个ScheduleDate条目,对于有5和7的员工,我希望在我工作时能让这两名员工回来运行此查询。然而,似乎当我运行它时,我只能回到一行。 (作为旁注,我正在使用的两个ScheduledDate条目是在同一天,但相隔约3小时。我认为DATEDIFF函数会解释这个,因为几个小时肯定在一天的时间框架。)如果我将查询中的=更改为> = 0或< = 0,我会按预期获得更多行,但奇怪的是仍然只获得该特定日期的单个条目。表中还有其他记录,其中同一个员工在不同日期有多次访问,并且当我使用> = 0或< = 0时,相应地返回这些记录。例如,具有Id 41的员工在10-29上有3次访问-2011,11-24-2011和12-28-2011,当我将DATEDIFF更改为> = 0时,所有这些都返回。我仍然很困惑为什么我只回到单个记录时两个不同的员工在同一天安排了访问。任何人都可以提供一些有关我的逻辑在哪里出错的见解吗?请注意,当我测试它时,我只提供ScheduledDate参数。所有其他IF IS NOT NULL语句都会失败,因为所有其他参数都被插入为NULL。

4 个答案:

答案 0 :(得分:1)

这是深入的,但它提供了非常丰富的信息:http://www.sommarskog.se/dyn-search.html

SET @sql = N'SELECT e.Id, e.FirstName, e.LastName, v.ScheduledDate
             FROM Employee e, Visit v
             WHERE v.EmpId = e.Id'

-- Several IF IS NOT NULL statements here
IF @d IS NOT NULL
  SET @sql = @sql + N' AND (v.ScheduledDate >= @date AND v.ScheduledDate < @date + 1)'

-- This stays the same, EVEN if the parameter is NULL and not used
-- This ensures execution plan re-use is available
SET @param_definition = '@date DATETIME,    -- Or whatever type v.ScheduledDate is
                         @smeg INT,
                         @head WHATEVER'

SP_EXECUTESQL
    @sql,
    @param_definition,
    @date = CAST(@d AS DATE),
    @smeg = 0,
    @head = NULL

答案 1 :(得分:0)

我认为最佳做法是删除日期的时间部分 这样做

DECLARE @dt DATETIME
SELECT @dt = GETDATE()
SELECT CAST(FLOOR(CAST(@dt AS FLOAT)) AS DATETIME)

那么你可以使用plain old =来比较

答案 2 :(得分:0)

我今天刚刚做了 SAME 的事情(用这行代码进行动态查询)。这是我的代码行:

DATEDIFF(day,SchDate,GetDate()) = 0

完美无缺。对不起,我不能再帮你了,但是我读了4次,我发现在约会部分没有任何错误。我做了同样的事情,它完美无缺。但是,如果您愿意,可以使用以下内容:

(AND day(@d) = day (v.ScheduledDate)) AND (month(@d) = month(v.ScheduledDate)) AND (year(@d) = year(v.ScheduledDate))

也许这会起作用(我只是用随机日期测试它,它确实如此)。你需要添加+ @ d +和东西,因为动态查询没有@d变量,但你已经知道= - )

希望这有帮助!

答案 3 :(得分:0)

这可能会有所不同,但我对您目前所描述的所有内容(包括您对Dems&#39;回答的评论)的最佳猜测是EmployeeVisit之间的关系并非仅由v.EmpId = e.Id定义,而是由复合键定义,并且您在连接/ where条件中缺少部分键。类似于v.EmpId = e.Id AND v.CompanyID = e.CompanyID