我有一张桌子
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
如何使用上述转换日期(第3列)进行比较? (需要加入?)
还有更好的方法吗?
编辑:我现在无法控制表格方案..我们建议更改数据库团队。现在必须坚持使用char(8)。
答案 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'
答案 2 :(得分:1)
我认为你应该避免在字符串类型字段中存储日期。如果这是你必须忍受的事情,请尝试以下解决方案。
由于您使用的是yyyymmdd
或yyyymm
格式,因此您可以先使用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)
字符串格式为YYYYMMDD
或YYYYMM
,但如果您决定开始使用格式为{{{的值,则该方法无需任何更改即可使用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)
我的建议是在表格中添加日期字段。如果您的表定期更新,请通过定期计划(触发器或作业)通过存储过程从旧字段填写它。
然后您可以将日期用作...日期,而不是所有这些技巧,转变和其他近似值,这些都是混淆,错误和可疑结果的潜在来源。