Переполнение DATEDIFF - PullRequest
       65

Переполнение DATEDIFF

0 голосов
/ 30 января 2020

Я использую следующий код в azure sql datawarehouse

SELECT cast(DATEDIFF(ms,cast(Start as datetime2),cast(EndTime as datetime2)
                        ) as float) AS [total]--difference to be calculated in millisecond
        FROM systable

, но обнаружил ошибку как «Функция datediff привела к переполнению. Число части даты, разделяющие два экземпляра даты / времени, слишком велики. Попробуйте использовать datediff с менее точной частью даты. "

Мое требование состоит в том, чтобы иметь разницу в миллисекундах, и если это изменится, это повлияет на другие результаты.

прошу вас оказать некоторую помощь

1 Ответ

0 голосов
/ 30 января 2020

Это происходит потому, что функция DATEDIFF () возвращает целое число. integer допускает значения только до 2 147 483 647. В этом случае у вас есть более чем 2B значений, вызывающих переполнение типа данных. В идеале вы должны использовать функцию DATEDIFF_BIG () , которая возвращает bigint , которая допускает значения до 9,223,372,036,854,775,807 или ~ 9 Septillion. DATEDIFF_BIG () не поддерживается в SQL Хранилище данных / Azure Synapse Analytics (по состоянию на январь 2020 года).

Вы можете проголосовать за эту функцию здесь: (https://feedback.azure.com/forums/307516/suggestions/14781627 )

Тестируя DATEDIFF (), вы можете увидеть, что вы можете получить ~ 25 дней и 20 часов разницы между датами, прежде чем исчерпать целые числа. Ниже приведен пример кода.

DECLARE @startdate DATETIME2 = '01/01/2020 00:00:00.0000';
DECLARE @enddate DATETIME2   = '01/01/2020 00:00:02.0000';

-- Support:
--   MILLISECOND:    ~25 days 20 Hours
--   MICROSECOND:    ~35 minutes
--   NANOSECOND:     ~ 2 seconds

SELECT
    DATEDIFF(DAY, @startdate, @enddate)             [day]
    , DATEDIFF(HOUR, @startdate, @enddate)          [hour]
    , DATEDIFF(MINUTE, @startdate, @enddate)        [minute]
    , DATEDIFF(SECOND, @startdate, @enddate)        [second]
    , DATEDIFF(MILLISECOND, @startdate, @enddate)   [millisecond]
    , DATEDIFF(MICROSECOND, @startdate, @enddate)   [microsecond]
    , DATEDIFF(NANOSECOND, @startdate, @enddate)    [nanosecond]

Тем временем вы можете рассчитать тики с начала времени для каждого значения и затем вычесть разницу. Для DATETIME2 вы можете рассчитать тики следующим образом:

CREATE FUNCTION dbo.DATEDIFF_TICKS(@date DATETIME2)
RETURNS BIGINT
AS
BEGIN

    RETURN
        (DATEDIFF(DAY, '01/01/0001', CAST(@date AS DATE)) * 864000000000.0)
        + (DATEDIFF(SECOND, '00:00', CAST(@date AS TIME(7))) * 10000000.0)
        + (DATEPART(NANOSECOND, @date) / 100.0);
END
GO

Затем вы можете просто запустить функцию и определить тики и разницу между тиками.

DECLARE @startdate DATETIME2 = '01/01/2020 00:00:00.0000';
DECLARE @enddate DATETIME2 = '01/30/2020 00:00:00.0000';

SELECT
    dbo.DATEDIFF_TICKS(@startdate)      [start_ticks],
    dbo.DATEDIFF_TICKS(@startdate)      [end_ticks],
    dbo.DATEDIFF_TICKS(@enddate) - dbo.DATEDIFF_TICKS(@startdate) [diff];

Вот пример пробег 500 лет отличий:

DECLARE @startdate DATETIME2 = '01/01/2000 00:00:00.0000';
DECLARE @enddate DATETIME2 = '01/01/2500 00:00:00.0000';

SELECT
    dbo.DATEDIFF_TICKS(@startdate)      [start_ticks],
    dbo.DATEDIFF_TICKS(@startdate)      [end_ticks],

    dbo.DATEDIFF_TICKS(@enddate) - dbo.DATEDIFF_TICKS(@startdate) [diff];

Результаты:

start_ticks          end_ticks            diff
-------------------- -------------------- --------------------
630822816000000000   630822816000000000   157785408000000000
...