【问题标题】:Get SQL Server DATEDIFF column as a TimeSpan when using SqlDataAdapter使用 SqlDataAdapter 时获取 SQL Server DATEDIFF 列作为 TimeSpan
【发布时间】:2017-02-20 05:15:32
【问题描述】:

在使用SqlDataAdapter 填充DataTable 时,是否可以将SQL Server 中DATEDIFF 函数的结果作为TimeSpan 获得?

作为一个非常简单的例子:

var table = new DataTable();
SqlCommand cmd = new SqlCommand(@"select DATEDIFF(mi, '2016-01-01', '2016-02-02') as [foo];", conn);
var da = new SqlDataAdapter(cmd);
da.Fill(table);
Console.WriteLine(table.Columns[0].DataType);

这会打印出System.Int32 而不是TimeSpan,并且在表格已经用table.Columns[0].DataType = typeof(TimeSpan); 填充后我无法更改DataType,因为它会引发异常。

我可以创建一个全新的 DataTable 并将数据复制到其中,但我不想这样做。

【问题讨论】:

  • 如果时差小于 24 小时,您可以投射到 time
  • 也可以通过 DateTime 值减去 DateTime.MinValue 得到 TimeSpan 值

标签: c# sql-server sqldataadapter


【解决方案1】:

SQL Server 没有自动映射到 .Net TimeSpan 的数据类型。您通常必须将跨度存储为 Int(或 BigInt),并在从适配器读取时将其转换为 TimeSpan

查看this post 获取一些示例。

【讨论】:

  • "当您从适配器读取时" - 这就是我想做的,但是SqlDataAdapter 中是否有任何钩子或回调或虚拟方法可以让我在阅读时进行转换?
  • 我从stackoverflow.com/a/9028126/492336 发现了有关 FillSchema,我认为这就是解决方案。
  • 我认为对于数据表,您必须拥有来自适配器的非 TimeSpan 列,然后您可以根据 db 值填充/添加另一个 TimeSpan 列
  • 无需转换,只需从生成的 DateTime 列中减去 DateTime.MinValue 即可。这可以作为计算列添加到数据表中
【解决方案2】:

在选择之前定义它:

    var table = new DataTable();
    SqlCommand cmd = new SqlCommand(@"select DATEDIFF(mi, '2016-01-01', '2016-02-02') as [foo];", conn);
    var da = new SqlDataAdapter(cmd);
    table.Columns.Add("foo", typeof(TimeSpan));
    da.Fill(table);
    Console.WriteLine(table.Columns[0].DataType);

编辑

但要小心。您正在使用带有 mi 参数的 DATEDIFF。但是当您将 foo 映射到 TimeSpan 时,这意味着将创建时间跨度,并将此分钟数解释为 Ticks。

所以要纠正它,你需要做这样的事情

select DATEDIFF(mcs, '2016-01-01', '2016-02-02')*10 as [foo]

因为滴答声是 100 纳秒单位。

但在大多数情况下它会导致SqlException: The datediff function resulted in an overflow.

【讨论】:

    【解决方案3】:

    也许这可能会有所帮助。这是我的 AGE 函数的修改版本,它返回年、月、日、小时、分钟和秒。

    TimeSpan 函数被缩减为天、小时、分钟、秒和毫秒。

    它可能看起来有点矫枉过正,但它非常准确,而且作为单语句 TVF,它非常快。

    作为 TVF,您可以单独使用、在 Join 中使用,甚至可以在 Cross Apply 中使用

    例如:

    Select * from [dbo].[udf-Date-TimeSpan] ('2016-07-29','2016-07-30 02:03:12.345')
    

    返回

    TimeSpan        Days  Hours Minutes Seconds Millisecond
    1.02:03:12.348  1     2     3       12      348
    

    需要的功能

    ALTER FUNCTION [dbo].[udf-Date-TimeSpan] (@D1 DateTime,@D2 DateTime)
    Returns Table
    Return (
        with cteBN(N)   as (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
             cteRN(R)   as (Select Row_Number() Over (Order By (Select NULL))-1 From cteBN a,cteBN b,cteBN c,cteBN d,cteBN e),  -- Max 100K Days or 273 Years
             cteDD(N,D) as (Select Max(R),Max(DateAdd(DD,R,@D1))From cteRN R Where DateAdd(DD,R,@D1)<=@D2),
             cteHH(N,D) as (Select Max(R),Max(DateAdd(HH,R,D))  From (Select Top 24 R From cteRN Order By 1) R, cteDD P Where DateAdd(HH,R,D)<=@D2),
             cteMI(N,D) as (Select Max(R),Max(DateAdd(MI,R,D))  From (Select Top 60 R From cteRN Order By 1) R, cteHH P Where DateAdd(MI,R,D)<=@D2),
             cteSS(N,D) as (Select Max(R),Max(DateAdd(SS,R,D))  From (Select Top 60 R From cteRN Order By 1) R, cteMI P Where DateAdd(SS,R,D)<=@D2),
             cteMS(N,D) as (Select Max(R),Max(DateAdd(MS,R,D))  From (Select Top 999 R From cteRN Order By 1) R, cteSS P Where DateAdd(MS,R,D)<=@D2)
    
        Select TimeSpan  = concat(cteDD.N,'.')+Format(cteHH.N,'00:')+Format(cteMI.N,'00:')+Format(cteSS.N,'00')+'.'+Format(cteMS.N-1,'000')
              ,[Days]    = cteDD.N
              ,[Hours]   = cteHH.N
              ,[Minutes] = cteMI.N
              ,[Seconds] = cteSS.N
              ,[Millisecond] = cteMS.N-1
         From  cteDD,cteHH,cteMI,cteSS,cteMS
    )
    --Select * from [dbo].[udf-Date-TimeSpan] ('2016-07-29','2016-07-30 02:03:12.345')
    

    编辑 - 也许是一个更好的插图

    Declare @Table table (Date1 Datetime,Date2 DateTime)
    Insert Into @Table values
    ('2016-01-01 00:00:00.200','2016-01-05 12:05:01.500'),
    ('2016-01-01 10:00:00.300','2016-01-05 12:30:30.500'),
    ('2016-01-01 10:00:00.800','2016-01-05 12:30:30.500')
    
    Select A.*
          ,B.TimeSpan
     From @Table A
     Cross Apply [dbo].[udf-Date-TimeSpan] (A.Date1,A.Date2) B
    

    返回

    Date1                       Date2                       TimeSpan
    2016-01-01 00:00:00.200     2016-01-05 12:05:01.500     4.12:05:01.300
    2016-01-01 10:00:00.300     2016-01-05 12:30:30.500     4.02:30:30.200
    2016-01-01 10:00:00.800     2016-01-05 12:30:30.500     4.02:30:29.700
    

    【讨论】:

      猜你喜欢
      • 2019-02-04
      • 1970-01-01
      • 2011-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-08
      • 1970-01-01
      • 2016-11-19
      相关资源
      最近更新 更多