AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 51440
Accepted
Martin Smith
Martin Smith
Asked: 2013-10-14 05:44:58 +0800 CST2013-10-14 05:44:58 +0800 CST 2013-10-14 05:44:58 +0800 CST

如何在 SQL Server 中将日期和时间组合到 datetime2?

  • 772

给定以下组件

DECLARE @D DATE = '2013-10-13'
DECLARE @T TIME(7) = '23:59:59.9999999'

将它们结合起来以产生DATETIME2(7)具有价值的结果的最佳方法是什么'2013-10-13 23:59:59.9999999'?

下面列出了一些不起作用的东西。


SELECT @D + @T 

操作数数据类型日期对于加法运算符无效。


SELECT CAST(@D AS DATETIME2(7)) + @T 

操作数数据类型 datetime2 对 add 运算符无效。


SELECT DATEADD(NANOSECOND,DATEDIFF(NANOSECOND,CAST('00:00:00.0000000' AS TIME),@T),@D)

datediff 函数导致溢出。分隔两个日期/时间实例的日期部分的数量太大。尝试将 datediff 与不太精确的日期部分一起使用。

* 在 Azure SQL 数据库和 SQL Server 2016 中,使用DATEDIFF_BIG.


SELECT CAST(@D AS DATETIME) + @T 

数据类型 datetime 和 time 在 add 运算符中不兼容。


SELECT CAST(@D AS DATETIME) + CAST(@T AS DATETIME)

返回结果但丢失精度2013-10-13 23:59:59.997

sql-server datatypes
  • 6 6 个回答
  • 64651 Views

6 个回答

  • Voted
  1. Best Answer
    ypercubeᵀᴹ
    2013-10-14T07:47:47+08:002013-10-14T07:47:47+08:00

    这似乎工作并保持精度:

    SELECT DATEADD(day, DATEDIFF(day,'19000101',@D), CAST(@T AS DATETIME2(7)))
    

    CASTto将值 ( )DATETIME2(7)转换为 date 部分所在的a ,这是 date 和 datetime 类型的默认值(请参阅MSDN上的注释*和页面。)TIME(7)@TDATETIME2'1900-01-01'datetime2CASTCONVERT

    * ... 当仅表示日期或仅表示时间分量的字符数据转换为 datetime 或 smalldatetime 数据类型时,未指定的时间分量设置为 00:00:00.000,未指定的日期分量设置为 1900-01- 01 .

    DATEADD()andDATEDIFF()函数负责其余部分,即添加 和 值 ( ) 之间的天1900-01-01数DATE差@D。

    测试:SQL-Fiddle


    正如@Quandary所注意到的,上述表达式被 SQL Server 认为是不确定的。如果我们想要一个确定性表达式,比如说因为它要用于PERSISTED列,则'19000101'**需要替换为0or CONVERT(DATE, '19000101', 112):

    CREATE TABLE date_time
    ( d DATE NOT NULL,
      t TIME(7) NOT NULL,
      dt AS DATEADD(day, 
                    DATEDIFF(day, CONVERT(DATE, '19000101', 112), d), 
                    CAST(t AS DATETIME2(7))
                   ) PERSISTED
    ) ;
    

    **:DATEDIFF(day, '19000101', d)不是确定性的,因为它对字符串的隐式转换DATETIME以及从字符串到日期时间的转换仅在使用特定样式时才具有确定性。

    • 54
  2. knuckles
    2017-04-22T02:20:58+08:002017-04-22T02:20:58+08:00

    我迟到了,但这种方法虽然类似于@ypercube 的回答,但避免了使用任何字符串转换(这可能比日期转换更昂贵)的需要,是确定性的,并且如果 MS 改变了应该继续工作1900-01-01 的默认日期值(即使他们可能不会更改此值):

    DECLARE @D DATE = SYSUTCDATETIME()
    , @T TIME = SYSUTCDATETIME();
    
    SELECT DATEADD(DAY, DATEDIFF(DAY, @T, @D), CONVERT(DATETIME2, @T));
    

    原理是,通过将时间值转换为 datetime2 然后再转换为日期,它会去除超时并分配默认日期,然后您可以使用您的日期值对它进行 datediff 以获取要添加的天数,将您的时间转换为 datetime2 并添加天。

    • 14
  3. Michael Green
    2018-07-16T19:40:50+08:002018-07-16T19:40:50+08:00

    对于 SQL Server 2012 及更高版本,有DATETIME2FROMPARTS函数。它有这种形式:

    DATETIME2FROMPARTS(year, month, day, hour, minute, seconds, fractions, precision)
    

    对于给定的样本数据,这变成

    select Answer = DATETIME2FROMPARTS(2013, 10, 13, 23, 59, 59, 9999999, 7);
    

    这导致

    Answer
    ---------------------------
    2013-10-13 23:59:59.9999999
    

    如果从时间数据类型开始,或者从用于构造问题中的样本值的文本开始,则可以使用DATEPART()获得这些部分。

    • 6
  4. Brian Jorden
    2019-07-30T05:03:49+08:002019-07-30T05:03:49+08:00

    当我降落在这里时,我正在寻找其他东西。这个问题已经很老了,但是最近有一些评论和活动。以为我会分享一个与@Atario 给出的答案非常相似的简单方法,但要短一些,有些人可能会觉得更容易阅读:

    declare @d date = '2013-10-13'
    declare @t time(7) = '23:59:59.9999999'
    
    select cast(concat(@d, ' ', @t) as datetime2(7))
    
    • 4
  5. Bogdan Sahlean
    2013-10-14T06:52:49+08:002013-10-14T06:52:49+08:00

    我已将两个值(@D 和 @T)都转换为二进制,我将二进制值连接起来,然后再转换回 DT2(7):

    SET NOCOUNT ON;
    
    DECLARE @D DATE = '2013-10-13'
    DECLARE @T TIME(7) = '23:59:59.9999999'
    DECLARE @DT2 DATETIME2(7) = '2013-10-13T23:59:59.9999999'
    
    SELECT CONVERT(BINARY(6), @T) AS T, CONVERT(BINARY(3), @D) AS D
    SELECT CONVERT(BINARY(9), @DT2) AS DT2
    SELECT CONVERT(BINARY(6), @T) + CONVERT(BINARY(3), @D) AS DT2_BinaryConcat
    
    DECLARE @DT2_AsBinary BINARY(9), @DT2_AsDateTime2 DATETIME2(7);
    SET @DT2_AsBinary = CONVERT(BINARY(6), @T) + CONVERT(BINARY(3), @D);
    SET @DT2_AsDateTime2 = CONVERT(DATETIME2(7), @DT2_AsBinary);
    SELECT @DT2_AsDateTime2 AS DT2_Converted;
    

    结果:

    T              D
    -------------- --------
    0x07FFBF692AC9 0xB1370B
    
    DT2
    --------------------
    0x07FFBF692AC9B1370B
    
    DT2_BinaryConcat
    --------------------
    0x07FFBF692AC9B1370B
    
    DT2_Converted
    ----------------------
    2013-10-13 23:59:59.9999999
    

    或者,更简洁:

    DECLARE 
        @D date = '2013-10-13',
        @T time(7) = '23:59:59.9999999';
    
    SELECT DT2 =
        CONVERT(datetime2(7), 
            CONVERT(binary(6), @T) + 
            CONVERT(binary(3), @D));
    

    该time(7)值被转换为binary(6)而不是记录的 5 字节存储大小,因为在转换为二进制时,SQL Server 会添加一个精度字节前缀以确保可以进行往返转换。这在但不是的脚注中记录。datetime2time

    在这种情况下,简单的连接有效,因为time精度与所需的datetime2精度相同。如果不是这样,您需要删除精度字节并将其替换为所需的值。

    此方法依赖于可能更改的实现细节,因此未记录且不受支持。

    db<>小提琴

    • 2
  6. Atario
    2014-06-11T11:32:11+08:002014-06-11T11:32:11+08:00

    SQL Server 不让你的第一个示例工作是相当愚蠢的,这看起来也很愚蠢,但是……

    select convert(datetime2, convert(nvarchar(max), @d) + ' ' + convert(nvarchar(max), @t));
    
    • 0

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    授予用户对所有表的访问权限

    • 5 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve