Преобразование временной части datetime2 в десятичный/плавающий

Я ищу способ построить критерии для поиска всех полуденных дат в поле datetime2 (включая значения, имеющие значение NULL). Другими словами, временная часть должна быть равна 0,5 или NULL. Вот что я пытался найти номер времени:

SELECT cast(GetDate() - DateDiff(day, 0, GetDate()) as decimal(4,4));

Это дает мне то, что я хочу, но когда я передаю его в качестве критериев, следующий код не с ошибкой

"Столкновение типа Operand: datetime2 несовместимо с int":

SELECT tbl_OrderDetailsSub.OrderDetailsSubID, ProcessedDate 
FROM tbl_OrderDetailsSub INNER JOIN tbl_OrderDetailsSubPl 
ON tbl_OrderDetailsSub.OrderDetailsSubID = tbl_OrderDetailsSubPl.OrderDetailsSubID 
INNER JOIN tbl_OrderDetails ON tbl_OrderDetailsSub.OrderDetailsID = tbl_OrderDetails.OrderDetailsID 
INNER JOIN tbl_Order ON tbl_OrderDetails.OrderID = tbl_Order.OrderID 
INNER JOIN tbl_Tooling ON tbl_OrderDetailsSubPl.TID = tbl_Tooling.TID LEFT OUTER JOIN tbl_ProdAct ON tbl_OrderDetailsSub.OrderDetailsSubID = tbl_ProdAct.ODSubID
WHERE (((tbl_Order.ProdTypeID)<>'S' Or (tbl_Order.ProdTypeID) Is Null) 
AND ((tbl_Order.CancelledDate) Is Null) 
AND ((tbl_Order.RefusingReason) Is Null)

AND (cast(isnull(ProcessedDate - DateDiff(day, 0, ProcessedDate),0.5) as decimal(4,4))=0.5)

AND ((tbl_Order.OrderType)<>'Pasiūlymas') 
AND ((tbl_Order.ShippedDate) Is Null));

Я чувствую, что он каким-то образом связан с функцией IsNull, но не может его прояснить. Я также попробовал эту строку

AND (cast(ProcessedDate - DateDiff(day, 0, ProcessedDate) as decimal(4,4))=0.5 OR ProcessedDate is null)

... но получилась такая же ошибка.

2 ответа

Ошибка заключается в том, что вы пытаетесь выполнить субтракт INT с DATETIME2, а INT не может быть явно преобразован в DATETIME2. Эта часть работает:

SELECT cast(GetDate() - DateDiff(day, 0, GetDate()) as decimal(4,4));

Поскольку GETDATE() является DATETIME, а не DATETIME2, а INT может быть неявно преобразован в DATETIME. Если вы проверите XML-код плана выполнения, вы увидите

CONVERT (десятичный (4,4), getdate() -CONVERT_IMPLICIT (datetime, dateiff (день, '1900-01-01 00: 00: 00.000', getdate()), 0), 0)

Если вы видите, что результат INT datediff(day,'1900-01-01 00:00:00.000',getdate()) неявно преобразуется в дату-время.

Вы можете воспроизвести ту же ошибку, используя:

DECLARE @D DATETIME2 = GETDATE();
SELECT cast(@D - DateDiff(day, 0, @D) as decimal(4,4));

Я не уверен на 100%, почему неявное преобразование было удалено для новых типов DATE и DATETIME2 в SQL Server 2008, но это было так, поэтому нам нужно иметь дело с этим.

Один из способов этого - просто преобразовать DATETIME2 в DATETIME:

DECLARE @D DATETIME2 = GETDATE();
SELECT cast(CAST(@D AS DATETIME) - DateDiff(day, 0, @D) as decimal(4,4));

Тем не менее, я был бы склонен избегать неявных преобразований полностью и использовать:

DECLARE @D DATETIME2 = GETDATE();
SELECT CAST(DATEDIFF(SECOND, '00:00', CAST(@D AS TIME)) / 86400.0 AS DECIMAL(10, 4));

Предпосылка превращает вашу дату в определенное время, а затем выясняет количество секунд до начала дня, а затем деление на полные секунды в день даст десятичное время.


Попробуй это

SELECT tbl_OrderDetailsSub.OrderDetailsSubID,
 ProcessedDate
FROM tbl_OrderDetailsSub
 INNER JOIN tbl_OrderDetailsSubPl
 ON tbl_OrderDetailsSub.OrderDetailsSubID = tbl_OrderDetailsSubPl.OrderDetailsSubID
 INNER JOIN tbl_OrderDetails
 ON tbl_OrderDetailsSub.OrderDetailsID = tbl_OrderDetails.OrderDetailsID
 INNER JOIN tbl_Order
 ON tbl_OrderDetails.OrderID = tbl_Order.OrderID
 INNER JOIN tbl_Tooling
 ON tbl_OrderDetailsSubPl.TID = tbl_Tooling.TID
 LEFT OUTER JOIN tbl_ProdAct
 ON tbl_OrderDetailsSub.OrderDetailsSubID = tbl_ProdAct.ODSubID
WHERE ( ( ( tbl_Order.ProdTypeID ) <> 'S'
 OR ( tbl_Order.ProdTypeID ) IS NULL )
 AND ( ( tbl_Order.CancelledDate ) IS NULL )
 AND ( ( tbl_Order.RefusingReason ) IS NULL )
 AND ( Cast(Isnull(Cast(ProcessedDate AS DATETIME) - Datediff(day, 0, Cast(ProcessedDate AS DATETIME)), 0.5) AS DECIMAL(4, 4)) = 0.5 )
 AND ( ( tbl_Order.OrderType ) <> 'Pasiūlymas' )
 AND ( ( tbl_Order.ShippedDate ) IS NULL ) );

licensed under cc by-sa 3.0 with attribution.