How to find the 1st date of previous month in mysql? - mysql

I am not able to run this function, is there any changes in this:
CREATE FUNCTION [GetFirstDateofMonth]
(#Date as DateTime)
RETURNS DateTime AS
BEGIN
Declare #FirstDate DateTime
Set #FirstDate = DateAdd(Day, 1, #Date - Day(#Date) + 1) -1
RETURN #FirstDate
END
CREATE FUNCTION [GetLastDateofMonth]
(#Date as DateTime)
RETURNS DateTime AS
BEGIN
Declare #LastDate DateTime
Set #LastDate = DateAdd(Month, 1, #Date - Day(#Date) + 1) -1
RETURN #LastDate
END

Assuming you want it relative to "now":
select subdate(adddate(last_day(now()), 1), interval 2 month)
replace now() with whatever you want if it's relative to some date other than "now"

Related

MySQL Procedure DATE Variable Operation

I'm new to MySQL, I've a date variable inside my MySQL procedure and I'm trying to find week start date for that IN date variable. My procedure goes as below,
CREATE PROCEDURE my_proc (IN week_start_num INT, IN my_date DATE)
BEGIN
DECLARE my_new_date DATE;
#I know what I'm trying here is wrong
SET my_new_date=startdate - (INTERVAL WEEKDAY( startdate ) - week_start_num + IF( WEEKDAY( startdate ) > week_start_num, 0, 7 ))
#rest of my codes goes here
END
I know this is wrong 'SET my_new_date =startdate - (INTERVAL WEEKDAY( startdate ) - week_start_num + IF( WEEKDAY( startdate ) > week_start_num, 0, 7 ))', what is the correct way to accomplish it?
Try this:
SET my_new_date = startdate
- INTERVAL
(
WEEKDAY(startdate)
- week_start_num
+ IF(WEEKDAY(startdate) > week_start_num, 0, 7)
)
DAY;

Check Each Date In Date Range

In SQL Server 2008 I have a startdate and an enddate being passed to my procedure. I need to check each date in the range to see if it exists in my validworkday table. I have no clue where to begin on this, but this is how start/end day are set-up
Declare #startdate date, #enddate date
Set #startdate = '01/01/2015'
Set #enddate = '04/16/2015'
Now how can I iterate each date in this span to see if validworkday = true for it? The check I would need to run is like so (checking each date)
Select isvalidworkday
from validworkdays
where date = '01/01/2015'
Select isvalidworkday
from validworkdays
where date = '01/02/2015'
This is syntax that I found from #Incidently years ago (I don't remember where that original post is, but hopefully this will be enough to give the credit), that I still use today. All I did was slightly tweak his syntax to insert the data into a temp table and add a cursor to iterate each individual date.
DECLARE #DateFrom smalldatetime, #DateTo smalldatetime, #firstdate date;
SET #DateFrom='20000101';
SET #DateTo='20081231';
-------------------------------
WITH T(date)
AS
(
SELECT #DateFrom
UNION ALL
SELECT DateAdd(day,1,T.date)
FROM T
WHERE T.date < #DateTo
)
SELECT date
INTO #AllDates
FROM T OPTION (MAXRECURSION 32767);
Declare c1 Cursor For
Select date
FROM #AllDates
Open c1
Fetch Next From c1 Into #firstdate
While ##FETCH_STATUS = 0
Begin
--Do whatever processing you need here
Fetch Next From c1 Into #firstdate
End
Close c1
Deallocate c1
Code should only live in one place and not be rewritten. Create functions (once) like GetAllIntsBetween(), GetAllMonths(), GetAllDates(), etc. Then used them like:
DECLARE #startdate date = '01/01/2015', #enddate date = '04/16/2015'
SELECT allDates.TheDate,
isnull(v.isvalidworkday, false) AS isvalidworkday
FROM dbo.GetAllDates(#startdate, #enddate) AS allDates
LEFT JOIN validworkdays AS v
ON allDates.TheDate = v.MyDate
The GetAllDates() would be:
CREATE FUNCTION dbo.GetAllDates(#Start DATETIME, #End DATETIME)
RETURNS
#AllDates TABLE
(
TheDate DATETIME
)
AS
BEGIN
IF #Start > #End
BEGIN
DECLARE #Temp DATETIME
SET #Temp = #Start
SET #Start = #End
SET #End = #Temp
END
WHILE #Start <= #End
BEGIN
INSERT INTO #AllDates
VALUES(#Start)
SET #Start = DATEADD(DAY, 1, #Start)
END
RETURN
END
(note: can change DATETIME to DATE)

Changing datetime value in MySQL

What I am trying to do, is to set beginning of time interval, if that is not correctly set into stored procedure. However, it somehow does not work very well..
This is my code:
CREATE PROCEDURE intervals_generator (IN start DATETIME, IN ending DATETIME, IN intervalis INT)
BEGIN
-- temp values
DECLARE next_date DATETIME;
-- result temp values
DECLARE start_temp DATETIME;
DECLARE ending_temp DATETIME;
-- date formatting variables
DECLARE year CHAR(20);
DECLARE month CHAR(20);
DECLARE day CHAR(20);
DECLARE new_start CHAR(20);
-- SET starting date if is incorrect DATE_FORMAT(NOW(), '%d %m %Y')
SET year := DATE_FORMAT(start, '%Y');
SET month := DATE_FORMAT(start, '%c');
SET day := DATE_FORMAT(start, '%e');
IF intervalis = '1_day' THEN
BEGIN
SET new_start := year+' '+month+' '+day+' 00:00:00';
END;
ELSEIF intervalis = '1_month' THEN
BEGIN
SET new_start := year+' '+month+' 1 00:00:00';
END;
ELSEIF intervalis = '1_quarter' THEN
BEGIN
IF MONTH(start) IN (2, 3) THEN
SET month := 1;
ELSEIF MONTH(start) IN (5, 6) THEN
SET month := 4;
ELSEIF MONTH(start) IN (8, 9) THEN
SET month := 7;
ELSEIF MONTH(start) IN (11, 12) THEN
SET month := 10;
END IF;
SET new_start := year+' '+month+' 1 00:00:00';
END;
ELSEIF intervalis = '1_year' THEN
BEGIN
SET new_start := year+' 1 1 00:00:00';
END;
END IF;
SET start := STR_TO_DATE(new_start, '%Y %c %e %h:%i:%s');
SELECT year, month, day, start;
DROP TEMPORARY TABLE IF EXISTS intervals_result;
END//
DELIMITER ;
I have tried many different formattings settings and functions, but the output is still wrong, like this:
mysql> CALL intervals_generator('2013-02-01 00:00:00', '2015-12-31 00:00:00', '1_year');
+------+-------+------+---------------------+
| year | month | day | start |
+------+-------+------+---------------------+
| 2013 | 2 | 1 | 2016-00-00 00:00:00 |
+------+-------+------+---------------------+
1 row in set (0.02 sec)
Query OK, 0 rows affected, 1 warning (0.02 sec)
I really dont understand why output is "2016-00-00" instead of "2013-01-01". year, month and day variables are defined as CHAR and also function that extracts them from datetime should be returning CHAR. And function STR_TO_DATE should also been taking CHAR format, so it is a mystery for me.
If anyone has some idea, please give me hint.
If you work in DATEs instead of strings, you can make use of MySQL's date functions and operators and make everything a whole lot simpler... but not too simple because this is MySQL.
The problem with MySQL and dates is its date functionality is a real mish-mash that sometimes works with DATEs, sometimes with strings, sometimes with integers, and is missing basic functionality. It lacks a simple function to set a piece of a date; there's no function to change the MONTH part of a DATE to February. There's not even a good way to make a date from the year, month and day, closest thing you get is MAKEDATE() which takes a year and the day of the year (?!). Fortunately, DATEs in MySQL respond to math operations and it's better than messing with strings.
If you have, for example, 2013-02-12 and want 2013-02-01 you have to first make a new date with just the year using MAKEDATE, then add the month part.
-- 2013-01-01
SET new_date := MAKEDATE(YEAR(old_date), 1);
-- 2013-02-01
-- Since MONTH returns from 1 to 12, you need to take away one.
SET new_date := new_date + (INTERVAL MONTH(old_date) - 1) MONTH;
After chopping out all the unused variables, changing to date math, and using the CASE statement instead of a big IF/ELSE chain, we get this:
CREATE PROCEDURE intervals_generator (IN start_date DATE, IN intervals TEXT)
BEGIN
DECLARE new_start DATE;
CASE intervals
WHEN '1_day' THEN
-- Nothing to do, DATE has already truncated the time portion.
SET new_start := start_date;
WHEN '1_month' THEN
-- Set to the year and month of the start date
SET new_start := MAKEDATE(YEAR(start_date), 1) + INTERVAL (MONTH(start_date) - 1) MONTH;
WHEN '1_quarter' THEN
BEGIN
-- Set to the year and month of the start date
SET new_start := MAKEDATE(YEAR(start_date), 1) + INTERVAL (MONTH(start_date) - 1) MONTH;
-- Subtract the necessary months for the beginning of the quarter
SET new_start := new_start - INTERVAL (MONTH(new_start) - 1) % 3 MONTH;
END;
WHEN '1_year' THEN
-- Set the date to the first day of the year
SET new_start := MAKEDATE(YEAR(start_date), 1);
END CASE;
SELECT new_start;
END//
Try it out.
This statement is not doing what you expect:
SET new_start := year+' '+month+' '+day+' 00:00:00';
In MySQL, the + operator does addition. That's it, not concatenation.
I think you intend:
SET new_start := concat(year, ' ', month, ' ', day, ' 00:00:00');
I haven't looked at the rest of the logic to see if it makes sense, but this is one glaring problem.
Instead of slicing and building new date from parts(concatenating) which is error-prone you can use built-in DATE_FORMAT:
SqlFiddleDemo
SET #date = '2013-05-03 10:05:00';
SELECT CAST(#date AS DATETIME) AS Date,
DATE_FORMAT(#date ,'%Y-01-01 00:00:00') AS Year_Allign,
CASE EXTRACT(QUARTER FROM #date)
WHEN 1 THEN DATE_FORMAT(#date ,'%Y-01-01 00:00:00')
WHEN 2 THEN DATE_FORMAT(#date ,'%Y-04-01 00:00:00')
WHEN 3 THEN DATE_FORMAT(#date ,'%Y-07-01 00:00:00')
WHEN 4 THEN DATE_FORMAT(#date ,'%Y-10-01 00:00:00')
ELSE NULL END AS Quarter_Allign,
DATE_FORMAT(#date ,'%Y-%m-01 00:00:00') AS Month_Allign,
DATE_FORMAT(#date ,'%Y-%m-%d 00:00:00') AS Day_Allign;
SqlFiddleDemo2
SET #date = '2013-05-03 10:05:00';
SET #allign = '1_QUARTER';
SELECT
CAST(#date AS DATETIME) AS Date,
CASE #allign
WHEN '1_YEAR' THEN DATE_FORMAT(#date ,'%Y-01-01 00:00:00')
WHEN '1_QUARTER' THEN (CASE EXTRACT(QUARTER FROM #date)
WHEN 1 THEN DATE_FORMAT(#date ,'%Y-01-01 00:00:00')
WHEN 2 THEN DATE_FORMAT(#date ,'%Y-04-01 00:00:00')
WHEN 3 THEN DATE_FORMAT(#date ,'%Y-07-01 00:00:00')
WHEN 4 THEN DATE_FORMAT(#date ,'%Y-10-01 00:00:00')
ELSE NULL END)
WHEN '1_MONTH' THEN DATE_FORMAT(#date ,'%Y-%m-01 00:00:00')
WHEN '1_DAY' THEN DATE_FORMAT(#date ,'%Y-%m-%d 00:00:00')
ELSE NULL
END AS Alligned;

Date Wise Report in SQL server 2008

How to get following output ?
[1],[2],[3],[4],[5],[6],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17]
,[18],[19],[20]
,[21],[22],[23],[24],[25],[26],[27],[28],[29],[30]
Need to fetch all dates from given month in sql server
I want to display daily Date Wise report
Example :
If I pass date as '11/01/2012' then it should return above result
and if I pass December than 31 days.
Very unclear question but try
DECLARE #epoch DATETIME = '20130101'
;WITH cte AS
(
SELECT #epoch DateKey
UNION ALL
SELECT DATEADD(D, 1, DateKey)
FROM cte
WHERE MONTH(DATEADD(D, 1, DateKey))=MONTH(#epoch)
)
SELECT * FROM cte
try below code
declare #date datetime = '09/10/2012'
declare #noofdays int
select #noofdays =datediff(day, #date, dateadd(month, 1, #date))
DECLARE #startDate DATETIME=CAST(MONTH(#date) AS VARCHAR) + '/' + '01/' + + CAST(YEAR(#date) AS VARCHAR) -- mm/dd/yyyy
DECLARE #endDate DATETIME= CAST(MONTH(#date) AS VARCHAR) + '/' + cast(#noofdays as varchar) + '/' + CAST(YEAR(#date) AS VARCHAR)
;WITH Calender AS
(
SELECT #startDate AS CalanderDate
UNION ALL
SELECT CalanderDate + 1 FROM Calender
WHERE CalanderDate + 1 <= #endDate
)
SELECT [Date] = CONVERT(VARCHAR(10),CalanderDate,25)
FROM Calender
OPTION (MAXRECURSION 0)
I am able to find out answer my self....
Thanks Buddy for trying to help me...
DECLARE #COLSPIVOT AS NVARCHAR(MAX)=''
declare #MaxDate int
set #MaxDate=(SELECT day(DATEADD(ms,-2,DATEADD(MONTH, DATEDIFF(MONTH,0,'8/1/2013')+1,0)))
AS [Current Month])
declare #i int =1
while (#i<=#MaxDate)
begin
set #COLSPIVOT=#COLSPIVOT+'['+convert(varchar(10),#i)+']'
if(#i!=#MaxDate)
begin
set #COLSPIVOT=#COLSPIVOT+','
end
set #i=#i+1
end
select #COLSPIVOT

SSRS default parameter values in subscription

I have a report that has two required date parameters which the user enters. I want to create a subscription that runs on Friday that pulls for the previous week's Sunday through Saturday period. So for example, for this coming Friday, the subscription would pull for Jan 29 - Feb 4. I've tried =Now(), =Today(), #ExecutionTime and then subtracting the number of days but all I get is errors. Is this possible to do?
I did see this link but I wonder if there's a better way.
http://www.sqlservercentral.com/articles/Development/datadrivensubscriptions/2432/
SSRS 2008
Yes I have done this, see this post https://stackoverflow.com/a/5539615/168703
You can create a dataset that gets date ranges and use it in your report. Then your subscription can use this date range and change on its own dynamically without manual changes every day/week/month/year/etc.
Reposted here as well, this is your most flexible solution:
I'll also share a set of common date functions I use. Just create this as a table valued function:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
CREATE FUNCTION [dbo].[udfCommonDates] (#date datetime)
RETURNS #t table (week_start datetime,
week_end datetime,
lastweek_start datetime,
lastweek_end datetime,
month_start datetime,
month_end datetime,
lastmonth_start datetime,
lastmonth_end datetime,
yesterday_start datetime,
yesterday_end datetime,
today_start datetime,
today_end datetime,
thisweek_monday_start datetime,
thisweek_monday_end datetime,
year_start datetime,
year_end datetime,
tomorrow_noon datetime,
today_noon datetime,
date_only datetime)
BEGIN
INSERT #t
SELECT
dbo.get_week_start ( #date ) AS week_start,
dbo.get_week_end ( #date ) AS week_end,
dbo.get_week_start ( DATEADD(d, -7, #date ) ) AS lastweek_start,
dbo.get_week_end ( DATEADD(d, -7, #date ) ) AS lastweek_end,
dbo.get_month_start( #date ) AS month_start,
dbo.get_month_end ( #date ) AS month_end,
dbo.get_month_start ( DATEADD(m,-1, #date) ) AS lastmonth_start,
dbo.get_month_end ( DATEADD(m,-1,#date) ) AS lastmonth_end,
dbo.get_yesterday_start ( #date ) AS yesterday_start,
dbo.get_yesterday_end ( #date ) AS yesterday_end,
dbo.get_today_start (#date) AS today_start,
dbo.get_today_end ( #date ) AS today_end,
dbo.get_weekday_start(1,#date) AS thisweek_monday_start,
dbo.get_weekday_end(1,#date) AS thisweek_monday_end,
dbo.get_year_start(#date) AS year_start,
dbo.get_year_end(#date) AS year_end,
dbo.get_tomorrow_noon(#date) AS TomorrowNoon,
dbo.get_today_noon(#date) AS TodayNoon,
dbo.get_date_only(#date) AS DateOnly
RETURN
END
Here are the scalar valued functions for these:
CREATE FUNCTION [dbo].[get_date_only] (#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN dateadd(day, DateDiff(day, 0, GetDate()), 0)
END
GO
CREATE FUNCTION [dbo].[get_month_end] (#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN dateadd(ms, -3, dateadd (m,datediff(m,0,
dateadd(m,1,#date)),0))
END
GO
CREATE FUNCTION [dbo].[get_month_start] (#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN dateadd(m,datediff(m,0, #date),0)
END
GO
CREATE FUNCTION [dbo].[get_today_end] (#today datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
return dateadd(ms, -3, datediff(d,0,dateadd(d,1,#today)))
END
GO
CREATE FUNCTION [dbo].[get_today_noon](#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
RETURN DATEADD(hh, 12, DATEADD(d,DATEDIFF(d,0, #date),0))
END
GO
CREATE FUNCTION [dbo].[get_today_start] (#today datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
return dateadd(day, 0, datediff(d,0,#today))
END
GO
CREATE FUNCTION [dbo].[get_tomorrow_noon](#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
RETURN DATEADD(hh, 12, DATEADD(d,DATEDIFF(d,-1, #date),0))
END
GO
CREATE FUNCTION [dbo].[get_week_end] (#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
return dateadd(yyyy, datepart(yyyy,
dateadd(weekday,7-datepart(weekday, #date),#date))-1900, 0)
+ dateadd(ms, -3,
dateadd(dy, datepart(dy,
dateadd(weekday,7-datepart(weekday, #date),#date)),0) )
END
GO
CREATE FUNCTION [dbo].[get_week_start] (#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
return dateadd(yyyy, datepart(yyyy,
dateadd(weekday,1-datepart(weekday, #date),#date))-1900, 0)
+ dateadd(dy, datepart(dy,
dateadd(weekday,1-datepart(weekday, #date),#date))-1,0)
END
GO
CREATE FUNCTION [dbo].[get_weekday_end] (#weekday tinyint,
#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
return dateadd(yyyy, datepart(yyyy,
dateadd(weekday,#weekday-
datepart(weekday, #date),#date))-1900, 0)
+ dateadd(ms, -3,
dateadd(dy, datepart(dy,
dateadd(weekday,#weekday-datepart(weekday, #date),
#date)),0) )
END
GO
CREATE FUNCTION [dbo].[get_weekday_start] (#weekday tinyint,
#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
return dateadd(yyyy, datepart(yyyy,
dateadd(weekday,#weekday-
datepart(weekday, #date),#date))-1900, 0)
+ dateadd(dy, datepart(dy,
dateadd(weekday,#weekday-datepart(weekday, #date),
#date))-1,0)
END
GO
CREATE FUNCTION [dbo].[get_year_end] (#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
RETURN DATEADD(year, DATEDIFF(year, 0, GetDate())+1, 0)-1
END
GO
CREATE FUNCTION [dbo].[get_year_start] (#date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
RETURN DATEADD(year,DATEDIFF(year,0, #date),0)
END
GO
CREATE FUNCTION [dbo].[get_yesterday_end] (#today datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
return dateadd(ms, -3, datediff(d,0,#today))
END
GO
CREATE FUNCTION [dbo].[get_yesterday_start] (#today datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS BEGIN
RETURN dateadd(day, -1, datediff(d,0,#today))
END
GO
These were really helpful for me because I used this in reporting services for date parameters. You could simply create a dataset referencing this table function and then use these in the parameters for any datetime within RS.
You could execute this entire table-valued function like so:
SELECT * FROM [MyDB].[dbo].[udfCommonDates] (GetDate())
The result is like so
For Reporting Services Folks
Now I mentioned earlier that I use these for reporting services.
Now the RS folks might be thinking but how does this help me as I need a dataset and a dataset can only be based on a Stored Procedure or a direct table. No problem create the following stored procedure:
CREATE PROCEDURE [dbo].[uspCommonDates] AS
begin
set datefirst 1
declare #date datetime
set #date = getdate()
select * from dbo.udfCommonDates(#date)
end
Now you've got a stored procedure to use as a dataset...Now in reporting services add a new dataset:
Now go to the report parameters section of the report:
Now pick that dataset dsFunctions (or whatever you called it) and then pick any of the value fields from the scalar functions such as:
Now when you run the report it uses the scalars:
Also now in your "Subscription" you will see a "Use Default" checkbox next to the
parameter for the date. If you check this checkbox it will automatically use the default
value provided by this custom function. It is very very flexible and a very nice solution in reporting services. Here is a screen print of that:
On the report parameter configuration (on development time, not on the subscription creation), add a default value for the parameter. If you do, you will have a check box called "use default value" when creating the subscription
My favorite trick to handle this situation is to create an Integer parameter called StartWeek. Prompt of "The week starting:" Available values like:
Value Label
-4 =dateadd("d",0-weekday(today)+2+(-4*7),today).ToString("m")
-3 =dateadd("d",0-weekday(today)+2+(-3*7),today).ToString("m")
-2 =dateadd("d",0-weekday(today)+2+(-2*7),today).ToString("m")
-1 Previous Week
0 Current Week
1 Last Month
2 This Month
Default value of -1.
Then in your query:
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
DECLARE #CurrentDate DATETIME
SET #CurrentDate = GETDATE()
--SET #CurrentDate = 'October 31, 2011' -- for debugging
IF ( #StartWeek > 0 )
BEGIN
SET #StartDate = DATEADD(mm, DATEDIFF(mm, 0, #CurrentDate), 0)
SET #StartDate = DATEADD(mm, 2 - #StartWeek, #StartDate)
SET #EndDate = DATEADD(s, -1, DATEADD(mm, 1, #StartDate))
END
ELSE
BEGIN
SET #StartDate = DATEADD(wk,
DATEDIFF(wk, 0, DATEADD(d, -1, #CurrentDate))
+ #StartWeek, 0)
SET #EndDate = DATEADD(s, -1, DATEADD(day, 7, #StartDate))
END
Select
*
FROM
MyTable
WHERE
BeginDate <= #EndDate
AND FinishDate >= #StartDate
BeginDate
=DateAdd("d", -12, Today())
EndDate
=DateAdd("d", -6, Today())
So for the upcoming Friday 2/10. This would give you a date range of 1/29 - 2/4.