2017-09-26 118 views
0

如果用户选择范围,如:检查日期落在月份和年份范围内

  • 开始:2016年11月
  • 结束9月2017年,

我想包括所有结果在2016-11-01至2017-09-30的范围内。

我试着将年,月和日连在一起,但问题是不是所有的月份都有相同的最后一天。虽然我知道所有月份从第01天开始,但一个月的结束日期可以是28,29,30或31.

有没有办法在不构建日期的情况下执行此操作? SqlServer 2008没有EOMONTH函数,我觉得比任何更复杂的东西都不是正确的解决方案。我想避免这种情况:

WHERE 
    DateCol >= '2016' + '-' + '11' + '-01' AND 
    DateCol <= '2017' + '-' + '09' + '-30' 
+3

'其中DATE_1> = '20161101' 和DATE_1 <=“20170930'' - 唯一真正安全的格式在SQL Server中的日期/时间文字,至少对于'datetime'和'smalldatetime',是:'YYYYMMDD'和'YYYY-MM-DDThh:mm:ss [.nnn]' - [踢坏的习惯:错误处理日期/范围查询 - Aaron Bertrand](http ://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/bad-habits-to-kick-mishandling-date-range-queries.aspx) – SqlZim

+2

https://blogs.msdn.microsoft.com/ samlester/2013/09/23/emonth-equivalent-in-sql-server-2008-r2-and-below/ – ttugates

+0

@SqlZim,我没有真正问过格式。年份和月份由用户选择。因此,如果他们选择了2017年9月,您怎么知道在“20170930”日期附加30? – user7733611

回答

1

在我看来,最简单和最好的答案是从开始的月份的第一个月到结束月份之后的月份的第一个月,并使第二个比较不包含在内。

换句话说,而不是这样的:

WHERE 
    DateCol >= '2016' + '-' + '11' + '-01' AND 
    DateCol <= '2017' + '-' + '09' + '-30' 

简单:

WHERE 
    DateCol >= '2016' + '-' + '11' + '-01' AND 
    DateCol < '2017' + '-' + '10' + '-01' 
+0

这似乎是一个好主意。但我不确定在12月的情况下我会做什么。这意味着我必须有条件地增加年份(并将月份从12更改为1)。 – user7733611

+0

使用'DATEADD(月,...)'功能很容易。 –

+0

@Sami,为什么不呢? –

0

在2008年,你可以简单地转换成字符串

Select Date1=convert(date,'November 2016') 
     ,Date2=dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017'))) 

返回

Date1  Date2 
2016-11-01 2017-09-30 

所以WHERE将是很重要的兴这样

... 
Where DateCol between convert(date,'November 2016') 
        and dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017'))) 
+0

我认为OP的问题是几个月,30或31或28的结束。 – Sami

0

你可以使用下面的SELECT语句传递一个字段或日期也得到任何一个月(及任何一年)的最后日期:

DECLARE @dtDate DATE 
SET @dtDate = '09/25/2016' 
SELECT CAST(DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@dtDate)+1,0)) AS DATE) AS LastDay_AnyMonth 

请提供一些示例数据和期望的结果,我会进一步更新我的答案。

+0

在寻找EOMONTH的替代方案时,我确实考虑了这一点。我最终想避免甚至必须弄清楚这个月的最后一天。 – user7733611

+0

你试图避免搞清楚这个月的最后一天是什么原因? – NonProgrammer

+0

我可以弄明白。但从逻辑上讲,它是不相干的,对吗?而是专注于比较几个月和几年。 – user7733611

0

在这里你去:

DECLARE @YourTable TABLE (YourData DATE); 


INSERT INTO @YourTable VALUES 
('2016-11-01'), 
('2016-09-05'), 
('2017-03-03'), 
('2017-11-11'), 
('2017-12-14'), 
('2017-09-30'); 

WITH CTE AS (
    SELECT YourData 
    FROM @YourTable 
    WHERE YEAR(YourData) =2016 AND MONTH (YourData) >= 11 
    ) 
    SELECT YourData 
    FROM @YourTable 
    WHERE YEAR(YourData) =2017 AND MONTH (YourData) <= 9 
    UNION ALL 
    SELECT YourData 
    FROM CTE; 

没有必要知道这个月(28或30或31)结束。

+0

这是行不通的。您排除2016年的数据。 – NonProgrammer

+0

你的答案仍然排除如2017-01-01 – user7733611

+0

@ user7733611的结果查看更新。 – Sami

1

有一种更快的方式做到这一点:

DECLARE @minDate DATE 
DECLARE @maxDate DATE 
SET @minDate = XXXXX 
SET @maxDate = YYYYY 

-- Get the first day of the month minDate. 
SET @minDate = CONVERT(datetime,CONVERT(varchar(6),@minDate,112)+'01',112) 
-- Get the last day of the month minDate. 
SET @maxDate = CONVERT(datetime,CONVERT(varchar(6),@maxDate,112)+'01',112) 
SET @maxDate = DATEADD(day, -1, DATEADD(month, 1, @maxDate)) 


SELECT * FROM myTABLE WHERE DateCol >= @minDate AND DateCol <= @maxDate 

或者:

SELECT * FROM myTABLE 
WHERE DateCol >= CONVERT(datetime,CONVERT(varchar(6),XXXXX,112)+'01',112) 
    AND DateCol <= DATEADD(day, -1, DATEADD(month, 1, CONVERT(datetime,CONVERT(varchar(6),YYYYY,112)+'01',112))) 

对于XXXXX和YYYYY而不是“2017-09-30”,使用类似CONVERT(datetime,'20170930',112)或CONVERT(datetime,'09 -30-2017',110)的语法,但使用SQL Server隐式从char到datetime转换(依靠服务器配置:可能有危险!!!))。

使用此语法更快,因为@minDate和@maxDate不需要任何评估。这样的索引,可以直接使用...

否则的标量函数将模拟EOMONTH()的行为可能是有用的...

+0

你介意解释这一行:CONVERT(datetime,CONVERT(varchar(6),XXXXX,112)+'01',112)112是什么? – user7733611

+1

112表示CONVERT期望第二个参数为日期的ISO文本格式:YYYYMMDD。 110适用于美国格式:MM-DD-YYYY。有关详细信息,请参见https://www.w3schools.com/sql/func_sqlserver_convert.asp ... – clementakis

+1

可以通过'SELECT CAST(getdate()AS VACHAR(20))'来检查日期到char的隐式转换格式。结果为您提供了SQL Server期望的文本格式。这可以从一台机器到另一台机器,即使在同一个compagny ... – clementakis

0

执行基于日期的操作的有用的结构是利用日期维度表。您正在创建一个查询表,该表包含大量关于日期的大量信息。然后,您可以根据您拥有的信息查询表格。该表格足够小,因此不会引起重大的性能问题。

在你的具体情况下,你有月份和年份。您可以将其插入日期维度表中,以获取从开始月份开始的月份的第一个月份和结束月份的月份的最后一个月份。您现在有一个时间范围可以在没有任何复杂逻辑或运算的情况下进行搜索。

阿龙贝特朗解释了它在这里深入:https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/

相关问题