2010-07-27 2 views
4

Первоначально это был вопрос о том, как реализовать это, потому что я застрял в определенной части, но мне теперь любопытно, почему это происходит в первую очередь. Мне нужно было сравнить только даты, а не время, которое не было бы проблемой, если бы времена не отличались. Приведенный ниже код показывает запрос я первоначально пыталсяSQL Date Compare, используя только дату Не время

SELECT * 
FROM Employee e 
inner join OT_Hours o on o.Emp_ID=e.Emp_ID 
inner join Position p on p.Position_ID=e.Position_ID 
inner join Signup_Sheet s on s.Employee_ID=e.Emp_ID 
WHERE e.Eligible_OT=1 and s.Day_Shift = 1 
and p.Position_Name = 'Controller' 
and Convert(Varchar(20),s.Date,101) = '07/26/2010' 
and Convert(Varchar(20),o.Date,101) <='07/26/2010' 
and Convert(Varchar(20),o.Date,101) > '07/26/2009' 
and o.Quantity NOT IN(0.3) order by o.Date DESC 

я не получил бы никакого результата, когда я побежал этот запрос, но когда я снял вторую последнюю строчку он будет возвращать 12 результатов (< =) и когда я удалил 3-я последняя строка, но вторая секунда вернет 6 результатов (>). После рассмотрения данных я мог видеть, что 4 из этих результатов должны были быть возвращены. Теперь о чужой части. Ниже приведен код, который я использую в настоящее время.

SELECT DISTINCT o.Date, e.Emp_ID as Emp_ID, e.First_Name+ ' ' +e.Last_Name as Name, o.Quantity as Sum 
FROM Employee e 
left join OT_Hours o on o.Emp_ID=e.Emp_ID 
left join Position p on p.Position_ID=e.Position_ID 
left join Signup_Sheet s on s.Employee_ID=e.Emp_ID 
WHERE e.Eligible_OT=1 and s.Day_Shift = 1 
and p.Position_Name = 'Controller' 
and Convert(Varchar(20),s.Date,101) = '07/26/2010' 
and o.Date between '07/26/2009' and '07/26/2010' 
and o.Quantity NOT IN(0.3) order by o.Date DESC 

Этот запрос будет возвращать результаты, но я проверил это, как я сделал другую, когда o.Date был выше и ниже указанной даты. Когда дата была < = 16 результатов были возвращены, когда> 8 результатов были возвращены. Окончательный запрос дал 6 результатов. Теперь это не производственная база данных, к которой я обращаюсь, и я использую ее только так, чтобы данные не менялись. Любое объяснение того, почему это происходит? Я предполагаю, что это как-то связано с преобразованием его в varchar, и оно не может сравниться правильно, но это не объясняет, почему я бы получил 12 < =, 6>, а затем никаких результатов в конце. Кроме того, если кто-то знает лучший способ реализовать это, пожалуйста, дайте мне знать.

+2

Это уже было задано (в некотором смысле). Проверьте принятый ответ здесь ... http://stackoverflow.com/questions/2775/whats-the-best-way-to-remove-the-time-portion -of-a-datetime-value-sql-server –

ответ

4

В третьей из последней строки в первом запросе вы сравниваете две строки.

В таком 01/02/2009 больше 01/01/2010

Я обычно делаю даты BETWEEN '01/02/2009 00:00:00.000' AND '01/01/2010 23:59:59.997', но это будет интересно увидеть лучшее решение.

+0

SQL Server выполняет неявное преобразование типа данных, переходя от строки к дате, предоставляя соответствие формату. –

+1

'SELECT CASE WHEN '01/02/2009 '> '01/01/2010' THEN 1 ELSE 0 END' возвращает 1 в моем SQL-поле. 'o.Date> '07/26/2009'' будет неявно преобразован, но не два varchars в соответствии с первым запросом. –

+0

Не вариант, но вы ответили на мой вопрос относительно того, почему он не сравнивал даты должным образом. Не понимаю, 1/02/2009 больше 01/01/2010 лол – Gage

1

Если база данных SQL Server, что я сделал, что работает довольно хорошо сдирать время что-то вроде следующего ....

SELECT DISTINCT o.Date, e.Emp_ID as Emp_ID, e.First_Name+ ' ' +e.Last_Name as Name, o.Quantity as Sum 
FROM Employee e 
left join OT_Hours o on o.Emp_ID=e.Emp_ID 
left join Position p on p.Position_ID=e.Position_ID 
left join Signup_Sheet s on s.Employee_ID=e.Emp_ID 
WHERE e.Eligible_OT=1 and s.Day_Shift = 1 
and p.Position_Name = 'Controller' 
and CAST(FLOOR(CAST(s.Date AS FLOAT)) AS DATETIME) = '07/26/2010' 
and CAST(FLOOR(CAST(o.Date AS FLOAT)) AS DATETIME) between '07/26/2009' and '07/26/2010' 
and o.Quantity NOT IN(0.3) order by o.Date DESC 

В зависимости от того, как установлены ваши параметры '07/26/2010 ', '07/26/2009', вы можете сохранить их в переменных времени и времени и выполнить ту же операцию cast(floor(cast(@datevar as float)) as datetime).

Это, кажется, repost. Проверьте принятый ответ здесь ... How to remove the time portion of a datetime value (SQL Server)?

7

Эти два запроса не совпадают - это:

and o.Date between '07/26/2009' and '07/26/2010' 

... является эквивалентом:

and o.Date >= '07/26/2009' 
and o.Date <= '07/26/2010' 

МЕЖДУ является стандартом ANSI , и включительно в каждую базу данных, с которой я когда-либо сталкивался.

Помните, что если вы не укажете временную часть для DATETIME, значение по умолчанию начнется в полночь дня - 00:00:00.

5

Я узнал эту технику из журнала SQL Server Февраль 2007 года (расчеты по дате времени от Itzik Ben-Gan). Таким образом, ваш «между» будет работать независимо от того, является ли дата в строке и после полуночи, как и все нормализована быть в полночь с этим сравнением:

select * 
from someTable 
where dateadd(day, datediff(day, 0, somedate), 0) between '07/26/2009' and '07/26/2010' 

DateDiff и DateAdd работают вместе, чтобы отогнать от времени и оставьте дату. Затем вы можете сравнить его с строковыми литералами или другими датами, которые имели ту же самую модификацию. Я бы рекомендовал включить это в функцию.

EDIT: Основано на комментариях OMG Ponies. Это не будет использовать индекс в столбце даты. Альтернативой может быть использование техники снятия времени в дополнение к технике, упомянутой выше.Поэтому вместо того, чтобы делать это в столбце таблицы, сделайте это на последнем аргументе «между». Вы могли бы иметь функцию следующим образом:

CREATE FUNCTION [dbo].[fn_enddate](@enddate datetime) 
RETURNS datetime AS 
BEGIN 
    DECLARE @endOfDay datetime 
    set @endOfDay = dateadd(millisecond, -2, dateadd(day, datediff(day, 0, @enddate) + 1, 0)) 
    return @endOfDay 
END 

Это принимает аргумент даты, устанавливает его в полночь на следующий день, а затем вычитает два миллисекунды, давая конец дня данного DateTime. И тогда вы могли бы сделать:

select * 
from someTable 
where somedate between '07/26/2009' and dbo.fn_enddate('07/26/2010') 
+0

Я этого раньше не видел. Приятно знать. Они говорили о '' CAST (FLOOR (CAST («метод тоже?» –

+0

Я не помню. Он сравнивал несколько, и этот, казалось, был лучшим. –

+1

Я не рекомендую использовать это - используя функция на столбце отображает индекс, если на месте, бесполезно –

1
... 
AND s.Date BETWEEN '2010-07-26 00:00:00.000' AND '2010-07-26 23:59:59.997' 
AND o.Date BETWEEN '2009-07-26 00:00:00.000' AND '2010-07-26 23:59:59.997' 
... 
1

Мое предложение было бы скорректировать ваши критерии, чтобы покрыть время, а не даты сами. Если вы конвертируете или иным образом обрабатываете столбцы (столбцы) для сравнения, вы можете уничтожить использование индексов в запросе.

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

В вашем случае, я хотел бы попробовать:

SELECT 
    o.Date, 
    e.Emp_ID as Emp_ID, 
    e.First_Name+ ' ' +e.Last_Name as Name, 
    o.Quantity as Sum 
FROM 
    Employee e 
LEFT JOIN OT_Hours o ON o.Emp_ID = e.Emp_ID 
LEFT JOIN Position p ON p.Position_ID = e.Position_ID 
LEFT JOIN Signup_Sheet s ON s.Employee_ID = e.Emp_ID 
WHERE 
    e.Eligible_OT = 1 AND 
    s.Day_Shift = 1 AND 
    p.Position_Name = 'Controller' AND 
    (s.Date >= @signup_date AND s.Date < DATEADD(dy, 1, @signup_date)) AND 
    (o.Date >= @order_start_date AND o.Date < DATEADD(dy, 1, @order_end_date)) AND 
    o.Quantity NOT IN (0.3) 
ORDER BY 
    o.Date DESC 

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

Смежные вопросы