我的dbase具有6位数的日期格式,带有int数据类型('734503'= 01/01/2012)。 我已经能够成功地将这些转换为char:
SELECT CONVERT(char(12),dateadd(dd,(date_paid - 639906),'1/1/1753'),101)
FROM vouchers
WHERE date_paid = '734503'
这给了我01/01/2012的输出。 但是,如果我在这样的查询中搜索转换日期:
SELECT CONVERT(char(12),dateadd(dd,(date_paid - 639906),'1/1/1753'),101)
FROM vouchers
WHERE date_paid >= '09/01/2012' AND date_paid <= '09/30/2012'
为什么不进行转换?即使我在date_paid字段的WHERE语句中使用CONVERT,它不应该在那里工作吗?
我想我的问题是如何使用转换后的字符日期进行搜索而不必使用6位数日期?
答案 0 :(得分:1)
您的问题是您正在将INT列与STRING值进行比较,并期望它像解析日期一样解决...
WHERE date_paid >= '09/01/2012'
AND date_paid <= '09/30/2012'
-- date_paid is an INT (according to your question)
-- '09/01/2012' is a STRING
由于数据类型不同,因此存在 隐式 CAST()。你有效地做了......
WHERE CAST(date_paid AS VARCHAR(10)) >= '09/01/2012'
AND CAST(date_paid AS VARCHAR(10)) <= '09/30/2012'
-- NOTE: All of these values are now strings
-- They may LOOK like dates, but they're just strings
您真正需要做的是 显式地 将字符串操作为整数。
WHERE date_paid >= DATEDIFF(DAY, '01/01/1753', '09/01/2012') + 639906
AND date_paid <= DATEDIFF(DAY, '01/01/1753', '09/30/2012') + 639906
这也涉及隐式演员表。 DATEDIFF()只接受DATETIME数据类型,因此首先将字符串隐式地转换为DATETIME。
修改强>
另一种选择是将date_paid
字段CAST()转换为DateTime,然后将WHERE
caluse置于其上。这里的缺点是......
- 必须在每一行上完成CAST(),然后应用WHERE子句
- 这可以防止任何索引的使用并显着降低性能
上面的答案对常量值进行了所有操作,以便搜索到的字段可以在其原生状态下处理;因此允许使用索引。
答案 1 :(得分:1)
首先,如果可以,请更改数据库架构。 date_paid列的数据类型应该是datetime
或date
,而不是&#39; int&#39;或者&#39; char`。
...但是如果您遇到此架构,那么您的date_paid
值似乎是整数,其值693596代表1 jan 1900
。 (此日期是SQL Server零值映射到的位置。)因此,您需要做的就是移动或将搜索值偏移此量。
假设您要搜索的日期是今天,2012年10月19日
Declare @SearchDate DateTime = '20 Oct 2012'
然后将您的查询谓词写为:
Select * From vouchers
Where date_paid = DateDiff(day, 0, @searchDate) + 693596
确保构建查询,以便所有处理或计算都在date_paid
列的等号的其他侧完成(如我的示例所示)。这样查询处理器可以使用date_Paid
上的索引(如果存在)。如果查询在date_Paid
上有任何函数调用或其他计算,则查询必须读取整个表,并且不能使用其他可用的索引请参阅SARGable。
顺便说一下,我很好奇这个设计(这个大的整数用于表示日期)来自哪里,我注意到这个值恰好等于1900 * 365,这意味着在这方案,零值重新设置在零年1月1日(当基督出生时),这将很酷,除了你不能在SQL Server日期使用它因为SQL Server值表示日期为16位签名整数,将零映射到1900年1月1日,并限制为16位整数(-16,384)中的最小值,相当于1753年左右的某个日期。