在SQL中将字符串转换为日期时间

时间:2013-08-23 17:25:26

标签: sql sql-server

我正在从其他系统导入数据,日期时间以字符串格式存储:

20061105084755ES

yyyymmddhhmmss(es/ed)其中es为EST,ed为EDT。

过去30天我将不得不查询此表。我正在使用转换查询:

select convert(
    datetime,
    left(cdts, 4)+'-'+substring(cdts, 5,2)+'-'substring(cdts, 7,2)+' '+substring(cdts, 9,2) +':'+substring(cdts, 11,2)+':'+substring(cdts, 13,2)
as dt
from tb1
where dt < getdate()-30

我正在寻找一种更有效的查询,以减少所需的时间。该表有大约9000万条记录,查询将永远运行。

3 个答案:

答案 0 :(得分:2)

如果您正在执行计算,然后需要根据计算结果进行筛选,则运行时计算不会加快此查询的速度 - SQL Server将被强制执行表扫描。主要问题是您已选择将日期存储为字符串。由于各种原因,这是一个可怕的决定。字符串列是否至少索引?如果是这样,那么可能仅帮助获取过去30天的数据:

DECLARE @ThirtyDays CHAR(8);
SET @ThirtyDays = CONVERT(CHAR(8),DATEADD(DAY,DATEDIFF(DAY,0,GETDATE()),0)-30,112);

SELECT ...
WHERE cdts >= @ThirtyDays;

如果您需要从过去30天以外的所有历史记录中返回所有数据,这也无济于事,因为除非您只从索引列中提取数据,否则最有效的方法是检索大部分数据表中的数据是使用聚簇索引扫描。 (如果您正在检索一组较窄的列,则可以选择索引扫描,如果您有覆盖索引。)因此,在大多数情况下,您的瓶颈不是公式可以修复的,而是需要花费的时间实际检索大量数据,通过网络传输,并在客户端上呈现。

另外,顺便说一句,你不能这样做:

SELECT a + b AS c FROM dbo.somewhere
WHERE c > 10;
c中不存在

dbo.somewhere,它是SELECT列表中派生的表达式。 SELECT列表最后一次解析(在ORDER BY之前),因此您无法在WHERE子句中引用尚不存在的内容。典型的解决方法是重复表达式或使用子查询/ CTE。

答案 1 :(得分:1)

一个可能的选择是在表中添加日期列并在加载时填充该信息。这样,转换就在您需要查询之前完成。

然后,确保您在该字段上有一个索引,实际查询可以利用该索引。

答案 2 :(得分:0)

convert(datetime,stuff(stuff(stuff(datevalue, 9, 0, ' '), 12, 0, ':'), 15, 0, ':'))

    Convert(time,Dateadd(SECOND,
        Right(DateValue,2)/1,
        Dateadd(MINUTE,
                Right(DateValue,4)/100,
                Dateadd(hour,
                        Right(DateValue,6)/10000,
                        '1900-01-01')))) +
convert(datetime,LEFT(datevalue,8))

Link