可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I need a select to return Month and year Within a specified date range where I would input the start year and month and the select would return month and year from the date I input till today.
I know I can do this in a loop but I was wondering if it is possible to do this in a series selects?
Year Month
---- -----
2010 1
2010 2
2010 3
2010 4
2010 5
2010 6
2010 7
and so on.
回答1:
declare @date1 datetime,
@date2 datetime,
@date datetime,
@month integer,
@nm_bulan varchar(20)
create table #month_tmp
( bulan integer null, keterangan varchar(20) null )
select @date1 = '2000-01-01',
@date2 = '2000-12-31'
select @month = month(@date1)
while (@month < 13)
Begin
IF @month = 1
Begin
SELECT @date = CAST( CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,0,@date1))-1),DATEADD(mm,0,@date1)),111) + ' 00:00:00' as DATETIME )
End
ELSE
Begin
SELECT @date = CAST( CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,@month -1,@date1))-1),DATEADD(mm,@month -1,@date1)),111) + ' 00:00:00' as DATETIME )
End
select @nm_bulan = DATENAME(MM, @date)
insert into #month_tmp
select @month as nilai, @nm_bulan as nama
select @month = @month + 1
End
select * from #month_tmp
drop table #month_tmp
go
回答2:
Gosh folks... using a "counting recursive CTE" or "rCTE" is as bad or worse than using a loop. Please see the following article for why I say that.
http://www.sqlservercentral.com/articles/T-SQL/74118/
Here's one way to do it without any RBAR including the "hidden RBAR" of a counting rCTE.
--===== Declare and preset some obviously named variables
DECLARE @StartDate DATETIME,
@EndDate DATETIME
;
SELECT @StartDate = '2010-01-14', --We'll get the month for both of these
@EndDate = '2020-12-05' --dates and everything in between
;
WITH
cteDates AS
(--==== Creates a "Tally Table" structure for months to add to start date
-- calulated by the difference in months between the start and end date.
-- Then adds those numbers to the start of the month of the start date.
SELECT TOP (DATEDIFF(mm,@StartDate,@EndDate) + 1)
MonthDate = DATEADD(mm,DATEDIFF(mm,0,@StartDate)
+ (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1),0)
FROM sys.all_columns ac1
CROSS JOIN sys.all_columns ac2
)
--===== Slice each "whole month" date into the desired display values.
SELECT [Year] = YEAR(MonthDate),
[Month] = MONTH(MonthDate)
FROM cteDates
;
回答3:
You can use something like this: http://blogs.msdn.com/b/sqlazure/archive/2010/09/16/10063301.aspx
To generate the equivalent of a numbers table using date ranges.
But could you please clarify your inputs and outputs?
Do you want to input a start date, for example, '2010-5-1'
and end date, for example, '2010-8-1'
and have it return every month between the two? Do you want to include the start month and end month, or exclude them?
Here's some code that I wrote that will quickly generate an inclusive result of every month between two dates.
--Inputs here:
DECLARE @StartDate datetime;
DECLARE @EndDate datetime;
SET @StartDate = '2010-1-5 5:00PM';
SET @EndDate = GETDATE();
--Procedure here:
WITH RecursiveRowGenerator (Row#, Iteration) AS (
SELECT 1, 1
UNION ALL
SELECT Row# + Iteration, Iteration * 2
FROM RecursiveRowGenerator
WHERE Iteration * 2 < CEILING(SQRT(DATEDIFF(MONTH, @StartDate, @EndDate)+1))
UNION ALL
SELECT Row# + (Iteration * 2), Iteration * 2
FROM RecursiveRowGenerator
WHERE Iteration * 2 < CEILING(SQRT(DATEDIFF(MONTH, @StartDate, @EndDate)+1))
)
, SqrtNRows AS (
SELECT *
FROM RecursiveRowGenerator
UNION ALL
SELECT 0, 0
)
SELECT TOP(DATEDIFF(MONTH, @StartDate, @EndDate)+1)
DATEADD(month, DATEDIFF(month, 0, @StartDate) + A.Row# * POWER(2,CEILING(LOG(SQRT(DATEDIFF(MONTH, @StartDate, @EndDate)+1))/LOG(2))) + B.Row#, 0) Row#
FROM SqrtNRows A, SqrtNRows B
ORDER BY A.Row#, B.Row#;
回答4:
---Here is a version that gets the month end dates typically used for accounting purposes
DECLARE @StartDate datetime;
DECLARE @EndDate datetime;
SET @StartDate = '2010-1-1';
SET @EndDate = '2020-12-31';
--Procedure here:
WITH RecursiveRowGenerator (Row#, Iteration)
AS ( SELECT 1, 1
UNION ALL
SELECT Row# + Iteration, Iteration * 2
FROM RecursiveRowGenerator
WHERE Iteration * 2 < CEILING(SQRT(DATEDIFF(MONTH, @StartDate, @EndDate)+1))
UNION ALL SELECT Row# + (Iteration * 2), Iteration * 2
FROM RecursiveRowGenerator
WHERE Iteration * 2 < CEILING(SQRT(DATEDIFF(MONTH, @StartDate, @EndDate)+1)) )
, SqrtNRows AS ( SELECT * FROM RecursiveRowGenerator
UNION ALL SELECT 0, 0 )
SELECT TOP(DATEDIFF(MONTH, @StartDate, @EndDate)+1)
DateAdd(d,-1,DateAdd(m,1, DATEADD(month, DATEDIFF(month, 0, @StartDate) + A.Row# * POWER(2,CEILING(LOG(SQRT(DATEDIFF(MONTH, @StartDate, @EndDate)+1))/LOG(2))) + B.Row#, 0) ))
Row# FROM SqrtNRows A, SqrtNRows B ORDER BY A.Row#, B.Row#;
回答5:
DECLARE @Date1 DATE
DECLARE @Date2 DATE
SET @Date1 = '20130401'
SET @Date2 = DATEADD(MONTH, 83, @Date1)
SELECT DATENAME(MONTH, @Date1) "Month", MONTH(@Date1) "Month Number", YEAR(@Date1) "Year"
INTO #Month
WHILE (@Date1 < @Date2)
BEGIN
SET @Date1 = DATEADD(MONTH, 1, @Date1)
INSERT INTO #Month
SELECT DATENAME(MONTH, @Date1) "Month", MONTH(@Date1) "Month Number", YEAR(@Date1) "Year"
END
SELECT * FROM #Month
ORDER BY [Year], [Month Number]
DROP TABLE #Month
回答6:
Code below generates the values for the range between 21 Jul 2013 and 15 Jan 2014.
I usually use it in SSRS
reports for generating lookup values for the Month parameter.
declare
@from date = '20130721',
@to date = '20140115';
with m as (
select * from (values ('Jan', '01'), ('Feb', '02'),('Mar', '03'),('Apr', '04'),('May', '05'),('Jun', '06'),('Jul', '07'),('Aug', '08'),('Sep', '09'),('Oct', '10'),('Nov', '11'),('Dec', '12')) as t(v, c)),
y as (select cast(YEAR(getdate()) as nvarchar(4)) [v] union all select cast(YEAR(getdate())-1 as nvarchar(4)))
select m.v + ' ' + y.v [value_field], y.v + m.c [label_field]
from m
cross join y
where y.v + m.c between left(convert(nvarchar, @from, 112),6) and left(convert(nvarchar, @to, 112),6)
order by y.v + m.c desc
Results:
value_field label_field
---------------------------
Jan 2014 201401
Dec 2013 201312
Nov 2013 201311
Oct 2013 201310
Sep 2013 201309
Aug 2013 201308
Jul 2013 201307
回答7:
you can do the following
SELECT DISTINCT YEAR(myDate) as [Year], MONTH(myDate) as [Month]
FROM myTable
WHERE <<appropriate criteria>>
ORDER BY [Year], [Month]