SSIS expression previous date without DateAdd() - sql-server

Currently developing a package that passes an expression from a previous date to a filename. The current code I have is the following as a string variable:
(DT_WSTR,20)DATEPART("YYYY",Dateadd("DD",-1,dateadd("MM",datediff("MM",
(DT_DATE) "1900-01-01",getdate())-2, (DT_DATE) "1900-01-01")))
+ RIGHT("0"+(DT_WSTR,20)DATEPART("MM",Dateadd("DD",-1,dateadd("MM",datediff("MM", (DT_DATE) "1900-01-01",getdate())-5, (DT_DATE) "1900-01-01"))),2)
+ "01"
This currently produces the output of:
20171101
This is currently incorrect because I'd like the date to be from the previous year:
20161101
Here's the forumula I'd like:
Return the 1st day of the month that is 7 months in the past from today's date.
Example: 5/2/2017 would return 11/1/2017; 6/21/2017 would return 12/1/2016; 7/10/2017 would return 1/1/2017; etc.
Is this possible to do via a variable in SSIS?

Your expression can be modified (and simplified) to this
(DT_WSTR, 8)( ( YEAR( DATEADD( "MM", -7, GETDATE() ) ) * 10000 ) + ( MONTH( DATEADD("MM", -7, GETDATE() ) ) * 100 ) + 1 )
subtract 7 months from current date
multiply resulting year by 10000
subtract 7 months from current date
multiply resulting month by 100
add year-value, month-value and 1 (first day)
convert to string
Credit to #Rangani in Yesterday's date in SSIS package setting in variable through expression for "multiply and add instead of string concat" trick

SELECT LEFT(CONVERT(VARCHAR, DATEADD("MM", -6, '2017-05-02'), 112), 6) + '01'
SELECT LEFT(CONVERT(VARCHAR, DATEADD("MM", -6, '2017-06-21'), 112), 6) + '01'
SELECT LEFT(CONVERT(VARCHAR, DATEADD("MM", -6, '2017-07-10'), 112), 6) + '01'

Related

How to do sorting by Day and Hour field?

I have a string value as 07052018080504623
It represents MM DD YYYY HH MM SS MS
means
MM = 07, DD = 05, YYYY=2018, HH = 08, MM=05 , SS= 04, MS = 623
Now I have a table defined as
declare #t table (WorkRequestId varchar(100))
insert into #t values
('07052018080504623'),('07062018012756663'),('07062018020148130'),('07062018095201231'),
('07062018102203805'),('07062018103718059'),('07062018110304836'),('07062018115356135'),
('07062018120624983'),('07062018124035480'),('07062018080504623'),('07062018070504623')
select
*
from #t
The records should be sorted in ascending order such that
WorkRequestId
07052018080504623
07062018095201231
07062018102203805
07062018103718059
07062018110304836
07062018115356135
07062018120624983
07062018124035480
07062018012756663
07062018020148130
The cutoff time is 8PM of previous day to 19:59:59 PM of next day.
In our example, 05 is previous day while 06 is next day.
Also no transaction happens between 1AM - 7:59:59 AM of next day. It starts again from 8AM of next day and continues till
19:59:59 PM.
So when we encounter 07062018012756663, the DD=06 and HH = 01. It means 13HRs (i.e. 1PM) of 6th. Same for 07062018020148130 where DD=06 and HH = 02 (i.e. 2PM or 14Hrs).
But 07062018095201231 where DD=06 and HH = 09 means 9AM of 6th.
That is why
07062018095201231 comes before 07062018012756663 and 07062018020148130
while ordering
My attempt so far (not correct yet)
select
*
,DY=SUBSTRING([WorkRequestId],3,2)
,HH = SUBSTRING([WorkRequestId],9,2)
,CurrentDY=CONVERT(varchar(2), getdate(), 103)
from #t
order by left([WorkRequestId],8) +
cast(iif(
SUBSTRING([WorkRequestId],3,2) = '6',--CONVERT(varchar(2), getdate(), 103),
iif(cast(SUBSTRING([WorkRequestId],9,2) as int) between 1 and 7,
cast(SUBSTRING([WorkRequestId],9,2) as int)+12,SUBSTRING([WorkRequestId],9,2)),
cast(SUBSTRING([WorkRequestId],9,2)as varchar(4)))as varchar(20))
+right([WorkRequestId],7)
So, I guess you should realize by now that storing dates as strings (and in fact, storing anything in the wrong data type) is bad practice.
The correct solution is to change the database structure to hold that data as DateTime2 instead of a string. However, assuming this can't be done for some reason, you can get the results you want by converting the string values to datetime2, adding 12 hours where the hour is between 1 a.m. and 8 a.m., and sort by that date.
I've written my suggestion in a cumbersome way because I wanted to show every part of the process - I've used 3 common table expression though if can be done in a single query - again, that's just to illustrate every step of the solution:
;WITH CTEDateParts AS -- break down the string to it's parts
(
SELECT WorkRequestId,
SUBSTRING(WorkRequestId, 5, 4) As Year,
SUBSTRING(WorkRequestId, 1, 2) As Month,
SUBSTRING(WorkRequestId, 3, 2) As Day,
SUBSTRING(WorkRequestId, 9, 2) As Hour,
SUBSTRING(WorkRequestId, 11, 2) As Minute,
SUBSTRING(WorkRequestId, 13, 2) As Second,
SUBSTRING(WorkRequestId, 15, 3) As Millisecond
FROM #t
), CTEDates AS -- create datetime values from the string parts
(
SELECT WorkRequestId,
CAST(Year +'-'+ Month +'-'+ Day +'T'+
Hour +':'+ Minute +':'+ Second +'.'+ Millisecond As DateTime2(7)) As DateValue
FROM CTEDateParts
), CTEFixedDates AS -- add 12 hours for hours between 1 and 8 a.m.
(
SELECT WorkRequestId,
DateValue,
CASE WHEN DATEPART(HOUR, DateValue) >= 1 AND DATEPART(HOUR, DateValue) <= 8 THEN
DATEADD(Hour, 12, DateValue)
ELSE
DateValue
END As FixedDate
FROM CTEDates
)
-- finally, select order by the FixedDate column
SELECT WorkRequestId
FROM CTEFixedDates
ORDER BY FixedDate
Results:
WorkRequestId
07052018080504623
07062018095201231
07062018102203805
07062018103718059
07062018110304836
07062018115356135
07062018120624983
07062018124035480
07062018012756663
07062018020148130
07062018070504623
07062018080504623
You can try the following:
select
*
from #t
order by left (WorkRequestId, 8) + (case when SUBSTRING(WorkRequestId, 9,2) between '01' and '07' then CAST(SUBSTRING(WorkRequestId, 9,2) + 12 AS CHAR(2)) else SUBSTRING(WorkRequestId, 9,2) end) + SUBSTRING(WorkRequestId, 11,7)

Check if date falls within Month and Year range

If a user selects a range such as:
Start: November 2016
End: September 2017,
I want to include all results that fall within the range of 2016-11-01 to 2017-09-30.
I tried concatenating together the year, month, and day, however the issue comes that not all months have the same last day. While I know all months start on day 01, a month's end day can be 28, 29, 30, or 31.
Is there a way to do this without constructing the date? SqlServer 2008 doesn't have the EOMONTH function, and I feel like anything more complex than that is not the right solution. I would like to avoid this:
WHERE
DateCol >= '2016' + '-' + '11' + '-01' AND
DateCol <= '2017' + '-' + '09' + '-30'
It really seems to me that the easiest and best answer is to go from the first of the beginning month to the first of the month after the ending month, and make the second comparison not inclusive.
In other words, instead of this:
WHERE
DateCol >= '2016' + '-' + '11' + '-01' AND
DateCol <= '2017' + '-' + '09' + '-30'
simply this:
WHERE
DateCol >= '2016' + '-' + '11' + '-01' AND
DateCol < '2017' + '-' + '10' + '-01'
There is a faster way to do so :
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
Or :
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)))
Use syntax like CONVERT(datetime,'20170930',112) or CONVERT(datetime,'09-30-2017',110) for XXXXX and YYYYY rather than '2017-09-30' that use SQL Server implicit convertion from char to datetime (rely on the server configuration : can be hazardous!!!)).
Using this syntax is faster because #minDate and #maxDate do not need any evaluation. So that indexes can be used directly...
Otherwise a scalar function that will simulate the eomonth() behaviour could be usefull...
You could use following select statement to get last date of any month (and any year) by passing a field or date to it:
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
Please provide some example data and desired result and I will update my answer further.
Here you go:
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;
There is no need to know the end of the month (28 or 30 or 31).
For 2008, you can simply convert the string
Example
Select Date1=convert(date,'November 2016')
,Date2=dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017')))
Returns
Date1 Date2
2016-11-01 2017-09-30
So the WHERE would be somthing like this
...
Where DateCol between convert(date,'November 2016')
and dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017')))
A useful construct for performing date-based operations is to make use of a Date Dimension table. You are creating a lookup table that is populated with a lot of information about dates over a large span of time. You can then query the table based on the information that you do have. The table is small enough so that it does not impose significant performance concerns.
In your particular case, you have the month and year. You would plug that into the date dimension table to get the first of the month from the beginning month and the last of the month from the ending month. You now have a time range to search over without any complex logic or calculations on the fly.
Aaron Bertrand explains it in depth here: https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/

Add a number (13) to the month and change the day to the 1st of that month

I am sure this one is simple but I am having a difficult time figuring it out. I am trying to add 13 months to a date and that resulting month needs to default to the 1st day of the month.
Example:
Date: 1/25/2016
Query results: 2/1/2017
Here is the query I am using:
SELECT Dateadd(month,13,getdate())
This should work for you. Just replace GETDATE() with your date.
select dateadd(month, datediff(month, 0, dateadd(month, 13, GETDATE())), 0)
SQL 2012+
SELECT DATEADD(DAY, 1, EOMONTH(GETDATE(), 12))
You can just construct the date from the constituent parts, by adding 1 year + 1 month and forcing the day part to 1 (and taking care of the special case of month = 12), like this:
select DATEFROMPARTS (
year(getdate()) + case when month(getdate()) = 12 then 2 else 1 end,
case when month(getdate()) = 12 then 1 else month(getdate()) + 1 end,
1
)

Error with SQL CONVERT GETDATE() for leap years

What I'm trying to do here is add a time component to GETDATE() since it's being converted to varchar(25). This is my statement, how would I do it?
CONVERT(Varchar(25),YEAR(GETDATE())-1)
Would it be something along CONVERT(Varchar(25),year(getDate()) -1)
This CONVERT is actually a part of:
DATEADD(m, 6,CAST(CONVERT(Varchar(25),MONTH(tblDateApt. Date)) +
'/' + CONVERT(Varchar(25),DAY(tblDateApt. Date))
+ '/' + CONVERT(Varchar(25),YEAR(GETDATE())-1) As DateTime))
The problem is when I run this statement on a leap year date I get an error. I'm trying to add a time to getDate before it gets casted as DATETIME
EDIT 2
I'm simply trying to make this give return a value...
select DATEADD(m, 6,CAST(CONVERT(Varchar(25),MONTH('2/29/2016')) + '/' + CONVERT(Varchar(25),DAY('2/29/2016')) + '/' + CONVERT(Varchar(25),YEAR(GETDATE())-1) As DateTime))
Breaking the date into strings and rebuild it into date is almost never the correct solution.
Assuming I understand the problem, you want to get the dates from your database, and manipulate the year part to be a year before the current year.
Try this:
SELECT tblDateApt.[Date],
DATEADD(Month,
6,
DATEADD(YEAR,
YEAR(GETDATE()) - 1 - YEAR(tblDateApt.[Date]),
tblDateApt.[Date])
)
FROM tblDateApt
Edited to get the date of 6 months after the date in the database after manipulating it to last year.
This will leave you with DateTime value taken from tblDateApt.Date decreased by one year and increased by 6 months (as per your intent):
SELECT DATEADD(month,
6,
DATEADD(year,
YEAR(GETDATE()) - YEAR(tblDateApt.date) - 1,
tblDateApt.date
)
)
Avoid any conversions to and from text content.

Get the amount of days in a month - mdx

In TSQL I can do this to get the amount of days in some month:
declare #date as datetime
set #date = '2015-02-06'
select datediff(day, dateadd(day, 1-day(#date), #date),
dateadd(month, 1, dateadd(day, 1-day(#date), #date)))
How can I get the same functionality in MDX?
P.S. I need the result to be an int.
If you have a year-month-date hierarchy in place, it could be done in the below fashion:
WITH MEMBER NumOfDaysInMonth AS
DateDiff(
"d",
HEAD(DESCENDANTS([Date].[Calendar Date].CURRENTMEMBER, 1)).ITEM(0).MEMBER_CAPTION, //Gets the first date of the month
TAIL(DESCENDANTS([Date].[Calendar Date].CURRENTMEMBER, 1)).ITEM(0).MEMBER_CAPTION //Gets the last date of the month
) + 1
You just need to to pass the month's value in the slicer. The calculated member will do the rest.
SELECT NumOfMonths ON 0
FROM [YourCube]
WHERE ([Date].[Calendar Date].[Month].&[Dec-2015])
This is the method we use:
WITH
MEMBER [MEASURES].[NumOfDaysInMonth] AS
IIF
(
VBA!Isdate([Date].[Calendar].CurrentMember.Name)
,Datepart
("D"
,
Dateadd
("M"
,1
,Cdate
(
Cstr(VBA!Month([Date].[Calendar].CurrentMember.Name)) + "-01-"
+
Cstr(VBA!Year([Date].[Calendar].CurrentMember.Name))
)
)
- 1
)
,''
)
SELECT
NON EMPTY
{[MEASURES].[NumOfDaysInMonth]} ON 0
,NON EMPTY
{
[Date].[Calendar].[All]
,[Date].[Calendar].[Calendar Year].&[2005]
,[Date].[Calendar].[Calendar Semester].&[2008]&[2]
,[Date].[Calendar].[Month].&[2006]&[3]
,[Date].[Calendar].[Date].&[20060214]
,[Date].[Calendar].[Month].&[2007]&[11]
} ON 1
FROM [Adventure Works];
The above returns the following:

Resources