我的表包含一个日期时间列。我只需要过去6个月才能返回行。这可以通过
来完成WHERE CloseTime >= DATEADD(Month, DATEDIFF(Month, 0, DATEADD(m, - 6, CURRENT_TIMESTAMP)), 0)
这为我提供了本月开始使用此脚本+ 6个月的数据。所以例如如果我今天运行这个脚本,我会得到本月+所有前几个月的数据,直到4月(04)。
现在我需要修改条件,所以如果我今天运行脚本,数据将只在03-09个月获得,不包括本月的日期(10)。
请问任何建议?
答案 0 :(得分:5)
如果你想拥有前6个月,无论今天是第1,第3,第9,第29,无论如何,那么只需减去7个月。这是一种方法:将月中的第一个变为变量,然后在查询中使用开放式范围。
DECLARE @ThisMonth DATETIME;
SET @ThisMonth = DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()), '19000101');
SELECT...
WHERE CloseTime >= DATEADD(MONTH, -7, @ThisMonth)
AND CloseTime < @ThisMonth;
您也可以使用0
代替'19000101'
,但我更喜欢明确的约会而不是隐含的速记(这是一个非常难以打破的习惯)。
如果你真的不喜欢变量,那么你可以通过重复表达来计算本月的第一个(并在范围的开头,从月数中减去7)来使查询复杂得多。 :
SELECT...
WHERE CloseTime >= DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE())-7, '19000101')
AND CloseTime < DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()), '19000101');
呸。变量使这更加整洁。
答案 1 :(得分:1)
创建查询时,您不希望在搜索列上使用某个函数,因为它会导致全表扫描。
解决方案有效,应该在CloseTime上获取任何索引。
-- Get me data in months 3 (mar) to 9 (sep) of this year
select
*
from
my_table
where
CloseTime between
DATEADD(d, -1, '03-01-2013') and DATEADD(d, +1, '09-20-2013')
如果表很小并且全表扫描不是问题,一个简单的解决方案是使用MONTH功能。
-- Get me data in months 3 (mar) to 9 (sep) of this year
select
*
from
my_table
where
MONTH(CloseTime) IN (3,4,5,6,7,8,9) and YEAR(CloseTime) = 2013
答案 2 :(得分:0)
我看了亚伦的文章。这是一个非常好的阅读。
我想知道自那篇文章以来是否有一些未经过测试的新功能。
如果您使用2012,为什么不使用格式功能?从逻辑上讲,您希望日期变量为01天。查询计划仍然会进行聚簇索引扫描。
让我们看看这个解决方案如何使用Aaron的测试数据库进行叠加。
-- Use the sample
use [DateTesting]
go
-- Johns - log by 6 months
CREATE PROCEDURE dbo.Johns_LogBy6Months
@date SMALLDATETIME
AS
BEGIN
SET NOCOUNT ON;
DECLARE @cmp_date SMALLDATETIME = format(@date, 'yyyyMM01');
DECLARE @c INT;
SELECT @c = COUNT(*)
FROM dbo.SomeLogTable
WHERE DateColumn >= dateadd(m, -7, @cmp_date)
AND DateColumn < @cmp_date
END
GO
-- Aarons - log by 6 months
CREATE PROCEDURE dbo.Aarons_LogBy6Months
@date SMALLDATETIME
AS
BEGIN
SET NOCOUNT ON;
DECLARE @c INT;
DECLARE @cmp_date SMALLDATETIME = DATEADD(MONTH, DATEDIFF(MONTH, '19000101', @date), '19000101');
SELECT @c = COUNT(*)
FROM dbo.SomeLogTable
WHERE
DateColumn >= dateadd(m, -7, @cmp_date)
AND DateColumn < @cmp_date
END
GO
让我们对函数进行1000次调用。
-- Sample calls x 1000
PRINT CONVERT(char(23), GETDATE(), 121);
GO
EXEC dbo.Johns_LogCountByDay @date = '20091005';
GO 1000
PRINT CONVERT(char(23), GETDATE(), 121);
GO
EXEC dbo.Aarons_LogBy6Months @date = '20091005';
GO 1000
PRINT CONVERT(char(23), GETDATE(), 121);
GO
这是执行时间。
2013-10-10 11:58:49.547
Beginning execution loop
Batch execution completed 1000 times.
2013-10-10 11:58:52.837
Beginning execution loop
Batch execution completed 1000 times.
2013-10-10 11:58:55.883
总之,对new format()函数的调用和对较小日期时间的隐式强制转换比使用两个字符串(日期)文字的dateadd()和datediff()花费更多的时间。
format()解决方案对我来说似乎更直观或自我记录。时差为3.3对3.0秒。
我必须为Aaron的解决方案提供速度测试。坚持日期变量的不等式比较。它们更快。
简而言之,我必须解决我的坏习惯。
答案 3 :(得分:0)
我有类似的要求。我需要过去六个月和接下来六个月的约会。但是就像你一样,我需要整整几个月的时间。因此,简单的getdate +-180不会。
我采用了更简单的方法。我得到年和月,然后将其转换为像201912这样的数字。然后执行一个between子句。它充满活力,我花了整整几个月的时间。
我敢肯定还有更复杂的方法,但这就是我想出的。
WHERE Year([ApptDate])*100 + Month([ApptDate]) between Year(getdate()-180)*100 + Month(getdate()-180) and Year(getdate()+180)*100 + Month(getdate()+180)