?
Solved

First day of the give Month and Year

Posted on 2014-02-22
7
Medium Priority
?
656 Views
Last Modified: 2014-02-24
Hello,
   I have a this stored procedure to which the year and month Number is pass as integer
   input.
   
For the SQL within that stored procedure, using the input month and Year (which is in integer data type), I need to derive a DATE as first day of that input month and year.

Eg:
CREATE PROCEDURE test (@i_Year INT, @i_Month INT)
BEGIN

  DECLARE @v_date DATE;
  SET @v_date = <need to assign 1st day of the input month/year i.e, '20140101'>

END

Input values passed to the stored procedure:
@i_Year = 2014
@i_Month = 1

Below is what I figured out:
SELECT 
CONVERT(DATE,     (CONVERT(VARCHAR,@v_Year)+CONVERT(VARCHAR,@v_Month)+'01')
               )

Open in new window


But is there a better way to achieve this?

Is there a date function which would take month and year, and return me the first day in that month/year, and also the value should be of type DATE?

Thanks!
0
Comment
Question by:sath350163
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
7 Comments
 
LVL 30

Expert Comment

by:Olaf Doschke
ID: 39880237
ISO date literals, eg '20140101' can be used - without CONVERT. There's implicit conversion done, so this works:

declare @v_date as date;

set @v_date ='20140301'

Open in new window


Change parameters to char(4) and char(2) or convert @iYear*100+@i_Month to a char(6) to concatenate '01'.

Bye, Olaf.

edit: ... or create a char(8) for implicit conversion:
set @v_date = convert(char(8),@i_Year*10000+@i_Month*100+1)

Open in new window


This just won't work with years before 1000, you'd have to add leading zeros, then.

Bye, Olaf.
0
 
LVL 35

Expert Comment

by:David Todd
ID: 39880306
Hi,

If you have a datetime, the easiest, fastest way is to keep it as a date time like this:

select dateadd( year, datediff( year, 0, getdate()), 0 )

Works for years, quarters, months, days, hours, minutes.

HTH
  David

PS converting to/from chars is slow - okay for a one-off, but not so much when grouping a bunch of transactions.
0
 
LVL 30

Assisted Solution

by:Olaf Doschke
Olaf Doschke earned 1000 total points
ID: 39880319
> dateadd( year, datediff( year, 0, getdate()), 0 )
That gives the first day of the current year.

dateadd( month, datediff( month, 0, getdate()), 0 )
gives the first day of the current month.

That's fine for these special cases, but no answer for the parameterisation of @i_Year, @i_Month.

So, Dave, you should explain 0 is taken as SQL Server default date 1900-01-01, so you could use the number of months to add to january, 1st 1900:

Select dateadd( month, (@i_Year-1900)*12+@i_Month-1, 0 )

eg:

declare @i_Year int, @i_Month int

set @i_Year = 2011
set @i_Month = 6

Select dateadd( month, (@i_Year-1900)*12+@i_Month-1, 0 )

Open in new window


Bye, Olaf.

Edit: I just did a little benchmark. Turns out dateadd is faster, that's no surprise. But it's just taking 40% of the char conversion.

I'm a bit surprised how much faster that is, actually. I wouldn't have thought a dateadd solution is more than twice as fast, even though it's two conversions (int->string->date) vs one date computation (dateadd) additional to a simple numeric computation, which would be neglectable in both cases.

declare @v_date date;
declare @t0 datetime;
declare @iJunk int;
declare @offset int;

use tempdb;
DECLARE @Dates table (iYear int, iMonth int);

Insert Into  @Dates
SELECT TOP 10000000 
RAND(checksum(newid()))*100+1950 as iYear, 
RAND(checksum(newid()))*12+1 as iMonth
FROM MASTER..spt_values a, MASTER..spt_values b;

--time to query all rows 
Select @t0=getdate();
Select @iJunk= iYear, @iJunk=iMonth from  @Dates;
--this is an offset time both of the following queries take just to query the data:
Select @offset = datediff(ms,@t0,getdate()); 
--subtract this time from both of the following results to get the net time for conversions.

--time to create a date with dateadd from 1900-01-01
Select @t0=getdate();
Select @v_date = dateadd( month, (iYear-1900)*12+iMonth-1, 0 ) from  @Dates;
Select datediff(ms,@t0,getdate())-@offset;

--time to create a date with conversion of int to char and implicit conversion of char to date
Select @t0=getdate();
Select @v_date = convert(char(8),iYear*10000+iMonth*100+1) from @Dates;
Select datediff(ms,@t0,getdate())-@offset;

Open in new window

0
Visualize your virtual and backup environments

Create well-organized and polished visualizations of your virtual and backup environments when planning VMware vSphere, Microsoft Hyper-V or Veeam deployments. It helps you to gain better visibility and valuable business insights.

 
LVL 35

Accepted Solution

by:
David Todd earned 1000 total points
ID: 39880896
Hi,

Howabout

declare @year int
declare @month int

set @year = 2011
set @month = 7

select dateadd( month, @month - 1, dateadd( year, @year - 1900, 0 ))

Open in new window

HTH
  David
0
 
LVL 30

Expert Comment

by:Olaf Doschke
ID: 39880982
Hi David,

of course that works, too. My benchmark says it's taking about two times as long, though. two vs one dateadd, quite logical.

So what's wrong with dateadd( month, (@i_Year-1900)*12+@i_Month-1, 0 )?

Too complicated?

Bye, Olaf.
0
 

Author Comment

by:sath350163
ID: 39881543
Appreciate the response from both of you.

Both the below approaches works well for my use case.

Select dateadd( month, (@i_Year-1900)*12+@i_Month-1, 0 )

select dateadd( month, @month - 1, dateadd( year, @year - 1900, 0 ))

Thanks a lot!
0
 
LVL 30

Expert Comment

by:Olaf Doschke
ID: 39882220
Thanks a bunch,

you could take it one step further and have a date generation function with year,month,day by using

dateadd(day, @day-1, dateadd( month, @month - 1, dateadd( year, @year - 1900, 0 )))

In your sepcific case the @day always is 1 and so the outer dateadd isn't needed. It's much harder to replace that with a single dateadd on day basis, as you'd need to compute days per year and month, with leap years and the differing month lengths etc.

It's easy enough to do with months only, though, and instead of starting from 0 start from day-1. So a generic solution with @year, @month and @day parameters could also be

dateadd(month, (@year - 1900) * 12 + @month - 1 , @day - 1)

Which would compare to C# DateTime(Int32, Int32, Int32) for year,month, day ints.

It's a pity T-SQL doesn't offer that simple date function in the first place, which was your original good question.

Bye, Olaf.
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this article I will describe the Copy Database Wizard method as one possible migration process and I will add the extra tasks needed for an upgrade when and where is applied so it will cover all.
This article explains how to reset the password of the sa account on a Microsoft SQL Server.  The steps in this article work in SQL 2005, 2008, 2008 R2, 2012, 2014 and 2016.
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This course is ideal for IT System Administrators working with VMware vSphere and its associated products in their company infrastructure. This course teaches you how to install and maintain this virtualization technology to store data, prevent vuln…

719 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question