如何通过使用where子句与字符串格式(varchar(103),...,10)将格式103格式化为分组

时间:2012-06-21 21:27:53

标签: sql sql-server datetime varchar

我在使用日期时间字段的查询时遇到问题。

因为我将datetime字段转换为-varchar(10),..,103-所以我可以在103格式而不是datetime上应用带有日期字段的where子句但是当我使用where子句时它不显示结果或者按我需要的方式分组,因为datetime字段已转换为字符串。

以下是该示例的简化查询:

select ddate,SUM(ntotal) as Income from Inc_orders    
where nbranch=2 
and convert(varchar(10),ddate,103)                                   
between '01/06/2010' and '31/06/2010'   
group by convert(varchar(10),ddate,103)  
order by ddfecha desc

ddate是日期时间字段
ntotal是整数
nbranch是外键

然后会发生的是我从另一个103日期范围获得结果

01/10/2009  4447.0000    
02/01/2010  26267.8000    
02/02/2010  20498.0000    
02/04/2010  22565.1000   
02/05/2010  20539.0000    
02/11/2010  33934.3000     
02/12/2009  33587.4000   

我假装看起来像是:

01/06/2010  29327.7000       
02/06/2010  31170.4000     
03/06/2010  37737.7000     
04/06/2010  25109.6000     
06/06/2010  20819.7000     
10/06/2010  44703.9000     
14/06/2010  21755.1000     
15/06/2010  39369.3000    
05/06/2010  29552.2000    
07/06/2010  35305.9000    
08/06/2010  30628.6000    
..........     
31/06/2010  18677.6000 

解决方案不使用datepart,month或year函数,因为我需要 参数看起来像日历,以在其上应用datetimepicker calentad组合对象。

4 个答案:

答案 0 :(得分:3)

请勿使用CONVERT(VARCHAR, DateField, 103)DATETIME中删除效率低的时间,并在排序时造成问题。

根据您使用的SQL-Server版本,有两个选项通常被视为最佳选项。对于SQL-Server 2008及以上使用CAST(DateField AS DATE),对于以前的版本,请使用DATEADD(DAY, 0, DATEDIFF(DAY, 0, DateField))

因为您要将Ddate转换为此行中的VARCHAR:

convert(varchar(10),ddate,103) between '01/06/2010' and '31/06/2010' 

您要删除'01 / 06/2010'和'31 / 06/2010'到日期的隐式转换。这意味着'02 / 01/2000'大于'01 / 01/2012',因为您正在比较字符串而不是日期。如果您从Ddate中删除时间并将表达式保持为日期(时间)格式,则'01/06/2010'和'31 / 06/2010'将隐式转换为日期。

为了说明这一点,您可以运行这个简单的查询:

SELECT  CASE WHEN '02/06/2000' BETWEEN '01/06/2012' AND '03/06/2012' THEN 1 ELSE 0 END [String Comparison],
        CASE WHEN CONVERT(DATETIME, '02/06/2000') BETWEEN '01/06/2012' AND '03/06/2012' THEN 1 ELSE 0 END [Date Comparison]

所以你的查询最终会是这样的:

SET DATEFORMAT DMY

SELECT  CAST(DDate AS DATE) Ddate,
        SUM(ntotal) as Income 
FROM    Inc_orders    
WHERE   nbranch=2 
AND     CAST(DDate AS DATE) BETWEEN '01/06/2010' AND '31/06/2010'   
GROUP BY CAST(DDate AS DATE)
ORDER BY DDate

或者

SELECT  DATEADD(DAY, 0, DATEDIFF(DAY, 0, DDate)) Ddate,
        SUM(ntotal) as Income 
FROM    Inc_orders    
WHERE   nbranch=2 
AND     DATEADD(DAY, 0, DATEDIFF(DAY, 0, DDate)) BETWEEN '01/06/2010' AND '31/06/2010'   
GROUP BY DATEADD(DAY, 0, DATEDIFF(DAY, 0, DDate))
ORDER BY DDate

<强>附录

我不确定Ddate是否包含时间,因此使用上述内容删除时间可能不相关,但是有关比较where子句中字符串的部分仍然相关。此外,只有很少的时候才需要以字符串格式向您的应用程序提供日期。最好将日期保留为日期并将其格式化在您的应用程序层中(无论这可能是什么)。

答案 1 :(得分:0)

不要在GROUP BY中使用CONVERT,也不要在WHERE中使用。在SELECT字段列表中使用转换

<强>更新
请参阅Microsoft的DATE CONSTANTS的有效和推荐格式。请选择“DATEFORMAT dependent:NO”和“Multilanguage:YES”的任何格式,以便在任何语言/设置中没有任何问题

<强>更新
当我看到时,我正在编写同样的查询@Blorgbeard:它不会工作,因为你不能只通过nbranch进行分组并且在选择列表上有ddate,而且在group by上的nbranch没有意义,因为只有有效值是2.你需要重新定义您的查询/需求

我想,您的查询可能是:

select ddate,SUM(ntotal) as Income from Inc_orders    
where nbranch=2 
and ddate  between '20100601' and '20100631'   
group by ddate   
order by ddate

答案 2 :(得分:0)

不要将日期转换为字符串,只需将其保留为日期:

select ddate,SUM(ntotal) as Income from Inc_orders    
where nbranch=2 
and ddate between '2010-06-01' and '2010-06-31'
group by nbranch   
order by ddate

如果您希望以特定方式显示,可以在选择列表中转换ddate

答案 3 :(得分:0)

您可以将文件日期转换为:

ISNULL(CONVERT(varchar(12),tranInwardHeader.DocumentDate,103),'') AS DocumentDate