Function to calculate month end in sql - sql

I have a table which has PlanTotal (how many plans), PlanStartDate (start date of plan) and PlanInstallment columns which tell me how many monthly payments the plan has left.
What coding would I need to work out
the date the plan will end and
how many plans are due to finish after today's date?
I also need to factor in that the PlanStartDate is in numeric value not datetime, so would need to convert this as well in the code.
Any help/ advice appreciated!

Here are many ways to format dates. I took GetDate() as the exemple.
DECLARE #NumericDate AS INT
SET #NumericDate = CAST(CONVERT(CHAR(10),GETDATE(),112) AS INT)
SELECT GETDATE() Today,
CONVERT(INT,GETDATE(),112) DateInt,
CAST(CONVERT(CHAR(10),GETDATE(),112) AS INT) DateNumeric,
YEAR(GETDATE())*10000 + MONTH(GETDATE())*100 + DAY(GETDATE()) AS DateNumeric_V2,
CONVERT(CHAR(10),GETDATE(),121) DateChar,
DATEADD(day,DAY(GETDATE())*-1,DATEADD(MONTH,1,GETDATE())) AS LastDayOfCurrentMonth,
SUBSTRING(CAST(#NumericDate AS CHAR(8)),1,4)
+ '-' + SUBSTRING(CAST(#NumericDate AS CHAR(8)),5,2)
+ '-' + SUBSTRING(CAST(#NumericDate AS CHAR(8)),7,2) AS NumericDate_2_String
And for the end date calculation you have DATEADD()
DECLARE #PlanInstallment as int
DECLARE #PlanStartDate AS INT
SET #PlanInstallment = 4
SET #PlanStartDate = 20140317
SELECT #PlanStartDate AS PlanStartDate,
DATEADD(MONTH,#PlanInstallment,GETDATE()) AS PlanEndDate
So with a mix of those 2 queries you should be able to do anything you want.

Related

SQL Server: convert and merge separate date and time columns (both integers)

I am working on a query, where I have to fill a table's column ([Result_DateTime]) with datetime values.
The datetime based on two columns, both integer. One contains the date and the other is the time, as it is.
As you can see from the picture, it is a bit difficult to merge and convert these values to an actual datetime, because of the way they are stored. Mainly the time value causing problems.
I concluded how to convert the date column:
CONVERT(DATETIME, LEFT(20200131, 8))
but then I got stuck - what to do with the time and how to merge the two into one datetime effectively?
Using function STUFF looks nasty...
Could you help me out please? I am using SQL Server 2014
Below is one method to do it:
SELECT CAST(Convert(DATE, LEFT(DATEUPDT, 8)) AS VARCHAR(10)) +' '+CAST (TIMEUPDT/100 AS VARCHAR(4)) + ':' + CAST(TIMEUPDT%(100 * (TIMEUPDT/100)) AS VARCHAR(10))+':00'
FROM TEST_TABLE_TIME;
I think I found one solution. What I tried is to avoid using varchar conversions because of how the time column's zeros are cut off. However, I am not convinced that this is the most effective way to do so:
DECLARE #DateInt int = 20200131
DECLARE #TimeInt int = 345 -- 03:45:00
SELECT CONVERT(DATETIME, LEFT(#DateInt, 8)) +
CAST(DATEADD(second, FLOOR(#TimeInt / 100) * 3600 + FLOOR(#TimeInt / 1) % 100 * 60, 0) as datetime)
I was testing it with various time values, it is working.

How to set month and day from one table to new stored procedure

declare
#pm_WeekEndDate DATETIME,
#lp_Day VARCHAR(10),
#intDate DATETIME
set #pm_WeekEndDate = MONTH(#pm_WeekEndDate)
set #lp_Day = day(#pm_WeekEndDate)
set #intDate = (#pm_WeekEndDate & #lp_Day)
This code should take month january then = 1 because other table has all in numbers like month 1 to 12 and day 1 to 7.
But I am getting this error:
Msg 402, Level 16, State 1, Procedure PRO, Line60
The data types datetime and varchar are incompatible in the '&' operator.
This is purely a guess by on extremely vague details and having this kind of poor table design in the past. Is something like this what you are looking for?
declare #pm_WeekEndDate DATETIME = getdate()
select #pm_WeekEndDate
declare #DateVal char(4)
select #DateVal = right('00' + convert(varchar(2), MONTH(#pm_WeekEndDate)), 2) + right('00' + convert(varchar(2), DAY(#pm_WeekEndDate)), 2)
select #DateVal
Please notice that you can't have the result be a date because it doesn't make sense. I am guessing that your table has dates stored as either strings or ints??

Convert datetime to numeric

I am trying to take a date which is in a varchar column in a table, add 1 day to it, and set it as the value of a datetime variable. This is part of a process that runs daily and I need to make sure the day resets to one at the end of the month. Or at the end of the year it doesn't increase from 151231 to 151232. The problem I am having is converting #Date back to numeric in the form YYMMDD. For example VIRN_CHK = '151231', #Date as written below is 'Jan 1 2016 12:00AM'. I need to convert it to 160101 so I can save it in a column in another table of type numeric(6,0).
DECLARE #Date as datetime
set #Date = convert(varchar,dateadd(d, 1,(select top(1) VIRN_CHK from STAGE_INST)))
update cdcdatei
set OT_DATE = #Date
This will work by rebuilding the string format
SELECT RIGHT(YEAR('2015-11-01'),2)
+ RIGHT('00' + CAST(MONTH('2015-11-01') AS VARCHAR(2)),2)
+ RIGHT('00' + CAST(DAY('2015-11-01') AS VARCHAR(2)),2)
So you need to extract the year, month and day numbers from the date? You can to that using DATEPART
DATEPART(yy,dateadd) AS DateYear,
DATEPART(mm,dateadd) AS DateMonth,
DATEPART(dd,dateadd) AS DateDay
then you can multiply and sum them to obtain what you need
VIRN_CHK = DateDay + DateMont * 100 + DateYear * 10000

SQL . The SP or function should calculate the next date for friday

I need to write a store procedure that will return a next friday date on a given date? for example - if the date is 05/12/2011, then it should return next friday date as 05/13/2011. If you pass, 05/16/2011, then it should return the date is 5/20/2011 (Friday). If you pass friday as the date, then it should return the same date.
I'd make this a scalar UDF as it is easier to consume the output.
CREATE FUNCTION dbo.GetNextFriday(
#D DATETIME
)
RETURNS DATETIME
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN DATEADD(DAY,(13 - (##DATEFIRST + DATEPART(WEEKDAY,#D)))%7,#D)
END
This is for SQL Server 2008. To use in 2005, just change the date fields to your preference for datetime to date conversions. It also assumes you are not changing the default week begin value.
DECLARE #PassedDate date = '5/21/2011';
SELECT DATEADD(DAY,(CASE DATEPART(DW,#PassedDate) WHEN 7 THEN 6 ELSE 6 - DATEPART(DW,#PassedDate) END),#PassedDate);
Similar to the top answer, but without using ##DATEFIRST in the solution:
DECLARE #Today DATETIME = GETDATE(); -- any date
DECLARE #WeekdayIndex SMALLINT = DATEPART(WEEKDAY, #Today);
DECLARE #DaysUntilFriday SMALLINT = (13 - #WeekdayIndex) % 7;
DECLARE #UpcomingFridayDate DATETIME = DATEADD(DAY, #DaysUntilFriday, #Today);
SELECT #UpcomingFridayDate ;
Great solutions here, but I also recommend looking at time tables: you can generate them easily in Analysis server, and they can be indexed to be very fast, giving you lots of easy ways to get next week days (among other things).
You can find out more about them here
In our case, the same solution would be
Select MIN(PK_Date) from Time Where PK_Date > #SomeDate AND Day_Of_Week= 6
And of course when you're doing this for a large recordset, you can also do joins for maximum speed & efficiency.

A better way? Have date in query always use a date in the current year without maintenance

SELECT Date_Received, DateAdd(Year, DateDiff(year, Cast('3/01/2010 12:00:00AM' as DateTime) ,
GetDate())-1, Cast('3/01/2010 12:00:00AM' as DateTime)) as minimum_date
FROM [Volunteers].[dbo].[Applications]
WHERE Date_received >= DateAdd(Year, DateDiff(year, Cast('3/01/2010 12:00:00AM' as DateTime),
GetDate())-1, Cast('3/01/2010 12:00:00AM' as DateTime))
In several subqueries where I need to check that a date is within an acceptable range. I need to avoid using a simple constant as I really don't want to update it or a config file each new school year.
My current solution is to enter the date into the query and use some complicated DATEADD tricks to get the current year(or previous year) into the date I am using in the comparison. The exact code is above. Is there a cleaner way for me to do this?
Thanks
Edit
The business requirement is to find applications submitted between 3/01 and 7/31.
We are running background checks and it costs us money for each check we do. Identifying applications submitted during this time period helps us determine if we should do a full, partial or no background check. I will also need to check if dates concerning the previous year.
We will be doing this every year and we need to know if they were in the current year. Maintaining the queries each year to update the dates is not something I want to do.
So I am looking for a good technique to keep the year parts of the dates relevant without having to update the query or a config file.
Old TSQL trick: cast the date to a string in a format that starts with the four-digit year, using substring to take the first four characters of that, cast it back to a date.
Actually, the reason that it's an old TSQL trick is that, if I recall correctly, there wasn't a year() function back then. Given that there's one now, using year( getdate() ) , as others' have answered, is probably the better answer.
SELECT YEAR(GETDATE())
will give you the current year.
If you need to query by month and year a lot, you should also consider making those properties into persisted, computed fields:
ALTER TABLE dbo.Applications
ADD DateReceivedMonth AS MONTH(Date_Received) PERSISTED
ALTER TABLE dbo.Applications
ADD DateReceivedYear AS YEAR(Date_Received) PERSISTED
SQL Server will now extract the MONTH and YEAR part of your Date_Received and place them into two new columns. Those are persisted, e.g. stored along side with your table data. SQL Server will make sure to keep them up to date automatically, e.g. if you change Date_Received, those two new columns will be recomputed (but not on every SELECT).
Now, your queries might be a lot easier:
SELECT (list of fields)
FROM dbo.Applications
WHERE DateReceivedYear = 2010 AND DateReceivedMonth BETWEEN 3 AND 7
Since these are persisted fields, you can even put an index on them to speed up queries against them!
Is there any reason you cannot simply use the Year function?
Select Date_Received
, Year(GetDate())
- Year('3/01/2010 12:00:00AM') - 1
+ Year('3/01/2010 12:00:00AM')
From [Volunteers].[dbo].[Applications]
Where Date_received >= ( Year(GetDate())
- Year('3/01/2010 12:00:00AM') - 1
+ Year('3/01/2080 12:00:00AM') )
Another way would be to use a common-table expression
With Years As
(
Select Year(GetDate()) As CurrentYear
, Year('3/01/2010 12:00:00AM') As ParamYear
, Year('3/01/2080 12:00:00AM') As BoundaryYear
)
Select Date_Received
, CurrentYear - Years.ParamYear - 1 + Years.ParamYear
From [Volunteers].[dbo].[Applications]
Cross Join Years
Where Date_received >= ( Years.CurrentYear
- Years.ParamYear - 1 + Years.BoundaryYear )
TSQL Function returns four digit year dependent on year. This behaves much like the standard SQL YEAR functions [Thomas - nod] which 'CAN' be tweaked using sp_configure on the advanced options, however, the code below is provided as a framework for CUSTOM requirements and can be modified as required. e.g. return as int, use with standard DATETIME functions in SQL to achieve what is needed. e.g. When working with "dirty" data I had to migrate, I used it with the PATINDEX() function to strip non-numeric values etc.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Andrew McLintock
-- Create date: 13 July 2016
-- Description: Return 4-digit YEAR
-- =============================================
/*
SELECT Staging.fn_4year('06')
SELECT Staging.fn_4year('56')
SELECT Staging.fn_4year('99')
SELECT Staging.fn_4year('1906')
SELECT Staging.fn_4year('2025')
*/
CREATE FUNCTION Staging.fn_4year
(
#year_in varchar (4)
)
RETURNS varchar(4)
AS
BEGIN
DECLARE #yeartmp int, #Retval varchar(4)
SET #yeartmp = CAST(REPLACE(#year_in,' ','') AS INT)
IF LEN(CAST(#yeartmp AS Varchar)) = 4
BEGIN
Return cast(#yeartmp as varchar(4))
END
IF LEN(#year_in) = 2
BEGIN
SET #Retval = CAST(iif(#yeartmp > 49, #yeartmp + 1900, #yeartmp + 2000) AS varchar(4))
END
RETURN #Retval
END
GO
Consider keeping a set of datetime variables help readability and maintainability. I'm not sure I've captured all your requirements, especially with reference to 'previous year'. If it's as simple as finding applications submitted between 3/01 and 7/31, then this should work. If you need to determine those that were submitted Aug 1 (last year) through Feb 28 (current year), this solution could be modified to suit.
DECLARE #Start smalldatetime, #End smalldatetime, #CurrYear char(4)
SELECT #CurrYear = YEAR(getdate())
SELECT #Start = CAST( 'mar 1 ' + #CurrYear as smalldatetime),
#End = CAST( 'jul 31 ' + #CurrYear as smalldatetime)
SELECT *
FROM Applications
WHERE Date_Received
BETWEEN #Start AND #End