哪个舍入舍入日期时间在 SQL 中更有效

Posted

技术标签:

【中文标题】哪个舍入舍入日期时间在 SQL 中更有效【英文标题】:which rounding rounding datetime is more efficient in SQL 【发布时间】:2021-01-13 08:50:48 【问题描述】:

我将编写一个对日期时间值进行舍入的代码,但我无法比较哪个更有效:

DECLARE @DateValue DATETIME = '2021-01-13 11:59:59'

---- FIRST SOLUSTION:
SELECT CAST(@DateValue AS smalldatetime) AS DateRoundS1


---- SECOND SOLUTION:
SELECT CONVERT(smalldatetime, @DateValue) AS DateRoundS2

---- THIRD SOLUTION:
SELECT DATEADD(HOUR, DATEDIFF(HOUR, 0, @DateValue), 0) AS DateRoundS3

---- FORTH SOLUTION:
DECLARE @DateValue DATETIME = '2021-01-13 11:59:59'
DECLARE @DiffMinsTime INT = DATEPART(MINUTE,@DateValue)
DECLARE @DiffSecsTime INT = DATEPART(SECOND,@DateValue)
DECLARE @DiffMSTime INT = DATEPART(MILLISECOND,@DateValue)

IF( @DiffMinsTime > 0 )
BEGIN
SELECT DATEADD(MINUTE,DATEDIFF(MINUTE,@DiffMinsTime,@DateValue),0)
END
    IF(@DiffSecsTime > 0)
    BEGIN
       SELECT DATEADD(SECOND,DATEDIFF(SECOND,@DiffSecsTime,@DateValue),0)
    END
       IF(@DiffMSTime > 0)
       BEGIN
            SELECT DATEADD(MILLISECOND,DATEDIFF(MILLISECOND,@DiffMSTime,@DateValue),0)
       END

PS:我知道最后一个溢出了!! 有没有更有效的方法来做到这一点?!

【问题讨论】:

什么是“高效”?正在尝试转换数百万行?告诉我们一些背景信息! 但是CASTCONVERT 非常快,但许多日期和时间函数也是如此(例如DATEADDDATEDIFF)。你想把时间“圆”到这里吗? Tip1 - 使用 DATETIME2 1 & 2 完全相同,CAST 只是调用CONVERT。 3也会很快。 4 看起来很慢。我通常做CAST(@DateValue AS date) 除了cast()/convert()之外,你为什么会考虑使用other 【参考方案1】:

对于转换和转换,它总是取决于很多因素。 最好的方法:建立一个测试台,并留出几分钟或更长时间。

测试台创建从 0 到 9 999 999 的数字 - 大约 1000 万行。感谢 Jeff Moden 创建数字列表的 SQL spackle。

DROP TABLE IF EXISTS #numbers
;
DROP TABLE IF EXISTS #dates
;
CREATE TABLE 
  #numbers
(
  number     integer NOT NULL
)
;
CREATE TABLE
  #dates
(
  dated      datetime2(7) NOT NULL
)
;
WITH
  cteNum
(
  smallnum
)
AS
(
  SELECT Cast( 1 AS integer )
  UNION ALL
  SELECT Cast( 2 AS integer )
  UNION ALL
  SELECT Cast( 3 AS integer )
  UNION ALL
  SELECT Cast( 4 AS integer )
  UNION ALL
  SELECT Cast( 5 AS integer )
  UNION ALL
  SELECT Cast( 6 AS integer )
  UNION ALL
  SELECT Cast( 7 AS integer )
  UNION ALL
  SELECT Cast( 8 AS integer )
  UNION ALL
  SELECT Cast( 9 AS integer )
  UNION ALL
  SELECT Cast( 0 AS integer )
)
INSERT INTO 
  #numbers
(
  number
)
SELECT 
  num1.smallnum * 1000000 + num2.smallnum * 100000 + num3.smallnum * 10000 + num4.smallnum * 1000
  + num5.smallnum * 100 + num6.smallnum * 10 + num7.smallnum
FROM
  cteNum AS num1
  CROSS JOIN cteNum AS num2
  CROSS JOIN cteNum AS num3
  CROSS JOIN cteNum AS num4
  CROSS JOIN cteNum AS num5
  CROSS JOIN cteNum AS num6
  CROSS JOIN cteNum AS num7
;
INSERT INTO
  #dates
(
  dated
)
SELECT 
  Cast( DateAdd( ms, nums.number, dated.basedate) AS datetime2(7) ) AS dated
FROM 
  #numbers AS nums
  CROSS JOIN 
  (
    SELECT Cast(GetDate() AS datetime2(7) ) AS basedate
  ) dated
;
DROP TABLE IF EXISTS #numbers
;

这将需要几秒钟到几分钟的时间来创建。 使用表可以最大限度地减少查询分析器对表进行维护的工作量。

然后可以在受控环境中进行转换时间测试。提示:使用开始和结束时间捕获可以消除 SQL 跟踪的开销。

SET NOCOUNT ON
;
DECLARE 
  @datetimestarted    datetime2(7),
  @datetimeended      datetime2(7),
  @result             varchar(200),
  @crlf               char(2) = char(13) + char(10)
;
SET @datetimestarted = Getdate()
;
SELECT
  dated,
  datedrounded = Cast( dated AS datetime2(0) )
FROM
  #dates
;
SET @datetimeended = Getdate()
;
SET @result = 'Processing time = ' + Cast( Datediff( ms, @datetimestarted, @datetimeended ) / 1000 AS varchar(12) ) + ' seconds' + @crlf
  + ' > Start time: ' + Convert( varchar(20), @datetimestarted, 126 ) + @crlf
  + ' > End time: ' + Convert( varchar(20), @datetimeended, 126 ) + @crlf
;
PRINT @result
;
SET @datetimestarted = Getdate()
;
SELECT
  dated,
  datedrounded = Convert( datetime2(0), dated )
FROM
  #dates
;
SET @datetimeended = Getdate()
;
SET @result = 'Processing time = ' + Cast( Datediff( ms, @datetimestarted, @datetimeended ) / 1000 AS varchar(12) ) + ' seconds' + @crlf
  + ' > Start time: ' + Convert( varchar(20), @datetimestarted, 126 ) + @crlf
  + ' > End time: ' + Convert( varchar(20), @datetimeended, 126 ) + @crlf
;
PRINT @result
;

每个选项在我的 VM 上的运行时间约为 3 分钟,其中 Cast 比 Convert 稍微长一点。现在这取决于人们想要实现的目标,因此请随意根据需要更改转换。

最后是清理。

DROP TABLE IF EXISTS #dates
;

最后提示:日期和日期时间是 SQL Server 中过时的日期时间类型。使用这些进行计算实际上比允许数学计算的新 datetime2 类型更容易。

datetime2 需要使用 Dateadd 函数。 但是 datetime2 更容易转换为不同类型的 RDBMS 之间的当前数据库交互。还更容易以标准 ISO 8601 格式工作,这使得在世界不同地区之间传输数据变得更加容易。

【讨论】:

以上是关于哪个舍入舍入日期时间在 SQL 中更有效的主要内容,如果未能解决你的问题,请参考以下文章

如何在熊猫数据框中舍入日期时间索引?

SimpleDateFormat 不解析毫秒,MySql 正在舍入日期

从日期中减去天数,然后将结果舍入到 Redshift 中的周末日期

SQL Server日期时间函数

数字日期和时间

Python数字日期和时间