Динамический SQL-запрос, возвращающий неожиданные результаты при сравнении дат - PullRequest
1 голос
/ 23 декабря 2011

Я строю динамический запрос как хранимую процедуру в SQL Server 2008 и получаю некоторые неожиданные результаты, когда сравниваю дату (предоставляется в качестве параметра) и дату и время (хранятся в базе данных).Я искал несколько способов сравнить два, не принимая во внимание временную часть, и нашел это:

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

Что я делаю с этим, пытаюсь найти записи, где указан предоставленный параметр даты и сохраненыScheduledDate одинаковы (в днях, например, 05.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)

Я ожидаю, что этот запрос приведет ко всем запланированным датам для любого сотрудника, у которого запланировано посещение на этот день.Другими словами, если у меня есть два сотрудника с идентификаторами 5 и 7 и в таблице посещений есть две записи ScheduleDate от 02.05.2011 для сотрудников с идентификаторами 5 и 7, я ожидаю, что оба этих сотрудника вернутся, когда язапустите этот запрос.Кажется, однако, что когда я запускаю его, я получаю только один ряд назад.(Как примечание, две записи ScheduledDate, с которыми я работаю, находятся в один и тот же день, но на расстоянии около 3 часов друг от друга. Я думаю, что функция DATEDIFF будет учитывать это, поскольку несколько часов, безусловно, находятся в пределахвременной интервал дня.) Если я изменю = в запросе на> = 0 или <= 0, я получу больше строк, как и ожидалось, но, как ни странно, все еще получаю только одну запись для этой конкретной даты.В таблице есть другие записи, в которых один и тот же сотрудник имеет несколько посещений в разные даты, и они возвращаются соответственно, когда я использую> = 0 или <= 0. Например, сотрудник с идентификатором 41 имеет 3 посещения 10-29-2011, 11-24-2011, 12-28-2011 и все 3 из них возвращаются, когда я изменяю DATEDIFF на> = 0. Я все еще не понимаю, почему я получаю только одну запись, когда два разных сотрудниканазначить визит на тот же день.Кто-нибудь может дать некоторое представление о том, где моя логика идет не так?Обратите внимание, что когда я тестирую это, я только предоставляю параметр ScheduledDate.Все остальные операторы IF NOT NOT NULL просто пропускаются, поскольку все остальные параметры вставляются как NULL.

Ответы [ 4 ]

1 голос
/ 23 декабря 2011

Это глубоко, но очень информативно: 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
0 голосов
/ 23 декабря 2011

Это может быть далеко, но мое лучшее предположение из всего, что вы описали (включая ваши комментарии к ответу Демс), заключается в том, что отношение между Employee и Visit определяется не только v.EmpId = e.Id , а скорее составной ключ, и вам не хватает его в вашем условии соединения / где. Что-то вроде v.EmpId = e.Id AND v.CompanyID = e.CompanyID.

0 голосов
/ 23 декабря 2011

Я только что сделал ЖЕ сегодня (динамический запрос с этой строкой кода). Это была моя строка кода:

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

Работало отлично. Извините, я не могу помочь вам в дальнейшем, но я прочитал это как 4 раза, и я не могу найти никаких ошибок в части датированных. Я сделал то же самое, что и вы, и это сработало безупречно. Однако, если вы хотите, вы можете использовать что-то вроде:

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

Может быть, это сработает (я только что проверил это со случайными датами, и это сработало). Ofc вам нужно добавить + @ d + и прочее, потому что динамический запрос не имеет переменной @d, но вы уже знаете, что = -)

Надеюсь, это поможет!

0 голосов
/ 23 декабря 2011

Я думаю, что лучшей практикой является удаление временной части даты сделать это так

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

тогда вы можете использовать просто старый = для сравнения

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...