将字符串转换为日期并将其用于比较

时间:2013-08-29 16:36:19

标签: sql sql-server

我有一张桌子

NUM | TDATE   
1   | 200712    
2   | 200708    
3   | 200704    
4   | 20081210

其中mytable创建为

 mytable
(
  num int,
  tdate char(8)  -- legacy 
);

tdate的格式为YYYYMMDD ..有时date部分是可选的。
所以像“200712”这样的日期可以解释为2007-12-01。

我想编写查询,以便将tdate视为日期列并应用日期比较。

喜欢

select num, tdate from mytable where tdate  

between '2007-12-31 00:00:00' and '2007-05-01 00:00:00'

到目前为止,我试过这个

select num, tdate,
CAST(LEFT(tdate,6) 
+ COALESCE(NULLIF(SUBSTRING(CAST(tdate AS VARCHAR(8)),7,8),''),'01') AS Date)
from mytable 

SQL Fiddle

如何使用上述转换日期(第3列)进行比较? (需要加入?)

还有更好的方法吗?

编辑:我现在无法控制表格方案..我们建议更改数据库团队。现在必须坚持使用char(8)。

7 个答案:

答案 0 :(得分:2)

我认为这是获得固定日期的更好方法:

SELECT CAST(LEFT(RTRIM(tdate) + '01',8) AS DATE)

您可以使用正确投射日期来创建子查询/ cte:

;WITH cte AS (select num, tdate,CAST(LEFT(RTRIM(tdate)+ '01',8) AS DATE)'FixedDate'
              from mytable )
select num, FixedDate
from cte
where FixedDate
between '2007-12-31' and '2007-05-01'

或者您可以直接在查询中使用固定日期:

select num, tdate 
from mytable 
where CAST(LEFT(RTRIM(tdate)+ '01',8) AS DATE) between '2007-12-31' and '2007-05-01'

理想情况下,您可以将固定日期字段添加到表中,以便查询可以从索引日期中受益。

注意:请谨慎对待BETWEEN DATETIME,因为如果您真的只关心DATE部分,时间部分会导致意外结果。

答案 1 :(得分:1)

'2007-12-31 00:00:00'> '2007-05-01 00:00:00',因此您的BETWEEN子句永远不会返回任何记录。

这将使用子查询,并且日期翻转:

select num, tdate, formattedDate
from 
(
  select num, tdate
  ,
  CAST(LEFT(tdate,6) + COALESCE(NULLIF(SUBSTRING(CAST(tdate AS VARCHAR(8)),7,8),''),'01') AS Date) as formattedDate

  from mytable 
) a
where formattedDate between '2007-05-01 00:00:00' and '2007-12-31 00:00:00'

sqlFiddle here

答案 2 :(得分:1)

我认为你应该避免在字符串类型字段中存储日期。如果这是你必须忍受的事情,请尝试以下解决方案。

由于您使用的是yyyymmddyyyymm格式,因此您可以先使用yyyymmdd格式Culture independent ISO format获取所有格式,然后使用style 112转换为比较日期:

--Culture independent solution
;with cte as (
  select num, tdate, 
         convert(date,left(rtrim(tdate) + '01',8),112) mydate --yyyymmdd format
  from mytable
)
select num,tdate,mydate
from cte
where mydate between convert(date,'20071231',112) and --Values are in yyyymmdd format
                     convert(date,'20070501',112) 

答案 3 :(得分:1)

将字符串值转换为日期的另一种方法是使用REPLACE

SELECT num, tdate
FROM mytable
WHERE CAST(REPLACE(tdate, '  ', '01') AS date) BETWEEN @date1 AND @date2
;

如果您确实要同时返回已转换的date,请将其用于过滤,您可以使用CROSS APPLY来避免重复逻辑:

SELECT t.num, t.tdate, x.date
FROM mytable AS t
CROSS APPLY (SELECT CAST(REPLACE(t.tdate, '  ', '01') AS date)) AS x (date)
WHERE x.date BETWEEN @date1 AND @date2
;

此方法假定您的char(8)字符串格式为YYYYMMDDYYYYMM,但如果您决定开始使用格式为{{{的值,则该方法无需任何更改即可使用1}}除了其他两种格式(暗示一年的开头,就像YYYY暗示一个月的开头)。

答案 4 :(得分:0)

with date_cte(num,date)as
(select num,CAST(LEFT(tdate,6) 
+ COALESCE(NULLIF(SUBSTRING(CAST(tdate AS VARCHAR(8)),7,8),''),'01') AS Date)
from mytable)

select t1.num, t1.tdate,t2.date
from mytable t1 join date_cte t2 on t1.num=t2.num
where t2.date 
between '2007-12-31 00:00:00' and '2007-05-01 00:00:00'

答案 5 :(得分:0)

我现在没有时间进行测试,但这样的事情可能有用......

select num, tdate
from mytable 
WHERE CAST(LEFT(tdate,6) 
+ COALESCE(NULLIF(SUBSTRING(CAST(tdate AS VARCHAR(8)),7,8),''),'01') AS Date) BETWEEN CAST('2007-12-31 00:00:00' as smalldatetime) and CAST('2007-05-01 00:00:00' as smalldatetime)

答案 6 :(得分:0)

我的建议是在表格中添加日期字段。如果您的表定期更新,请通过定期计划(触发器或作业)通过存储过程从旧字段填写它。

然后您可以将日期用作...日期,而不是所有这些技巧,转变和其他近似值,这些都是混淆,错误和可疑结果的潜在来源。