1

我有一张桌子

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小提琴

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

还有更好的方法吗?

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

4

7 回答 7

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

于 2013-08-29T16:47:13.113 回答
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在这里

于 2013-08-29T16:44:31.093 回答
1

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

由于您拥有yyyymmddoryyyymm格式,您可以先将它们全部以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) 
于 2013-08-29T16:46:47.543 回答
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)字符串被格式化为YYYYMMDDor YYYYMM,尽管如果您决定开始使用YYYY除其他两种格式之外的格式化值(暗示一年的开始,就像 aYYYYMM暗示月初)。

于 2013-09-02T10:02:38.253 回答
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'
于 2013-08-29T16:40:39.870 回答
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)
于 2013-08-29T16:42:54.130 回答
0

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

然后,您将能够将日期用作……日期,而无需所有这些技巧、周转和其他近似值,这些都是造成混淆、错误和可疑结果的潜在来源。

于 2013-08-29T16:53:56.517 回答