SQL Find/Ignore invalid date - sql

I am using SQL Server.
From each row, I take day and month values from the fields c.daybirth,c.monthbirth
and the year from getdate(), and I want to have a field that shows if this date is valid or not (invalid example: 31 February)
I have created this solution:
case day(dateadd(month,c.monthbirth-1,dateadd(day,c.daybirth-1,DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0)))) when c.daybirth then 1 else 0 end
which works, but I find it hard to read. Is there a smarter alternative?

In SQL Server 2012+, you can do:
where try_convert(date,
datefromparts(year(getdate()), c.monthbirth, c.daybirth)
) is not null
EDIT:
Amusing. This is better:
where try_convert(date,
cast(year(getdate()) * 10000 + c.monthbirth * 100 + c.daybirth as varchar(255))
) is not null

Related

Construct a date from parts in SQL Server 2008

I am using SQL Server 2008 and trying to form a query that will use a CASEstatement with a date calculation to return one of two dates depending on what day of the month the calculation results in.
The goal is if the calculation (in query below) CURRENT_TIMESTAMP + LEAD_TIME results in a day between the 1st and 15th, then assign the 15th of that month. Otherwise, return the last day of that month.
For example, if CURRENT_TIMESTAMP + LEAD_TIME = 07/12/19, return 07/15/19. If that calculation = 07/16/19, return 07/31/19.
This seems like it would be possible using DATEFROMPARTS but I believe since I am using SQL Server 2008 that function is not defined (that is the error I am returning). Any ideas on a work around?
SQL:
SELECT I.po_number,
I.po_item_number AS 'po_item',
S.orderentry_date,
I.po_req_ship_date,
I.ex_factory_date,
I.del_indicator,
H.po_type,
H.vendor_no,
CASE WHEN DATEPART(dd,(CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME)) BETWEEN 1 AND 15
THEN DATEFROMPARTS(DATEPART(yyyy,(CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME),mm,(CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME),15)
ELSE DATEFROMPARTS(DATEPART(yyyy,(CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME),mm,(CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME)+1,0))
END AS 'LT_CALC',
H.po_created_by,
I.comment
FROM rbk_sap_user..vw_po_header H
JOIN rbk_sap_user..vw_po_item I ON H.po_number = I.po_number
JOIN rbk_sap_user..vw_mm_material MM ON I.material = MM.material
JOIN (SELECT order_no,
orderentry_date
FROM asagdwpdx_prod..SimoxOrder1
UNION ALL
SELECT order_no,
orderentry_date
FROM asagdwpdx_prod..SimoxOrder2
UNION ALL
SELECT order_no,
orderentry_date
FROM asagdwpdx_prod..SimoxOrder3
) S ON S.order_no = H.ahag_number
WHERE S.orderentry_date BETWEEN '01/31/2019' AND '02/13/2019'
AND I.del_indicator <> 'L'
AND H.po_type NOT IN ('02','06','10','UB')
AND MM.business_segment_code NOT IN ('420','421','422','424')
You can convert all the parts of the date to VARCHAR and string them together to yyyy-mm-dd format, and then CONVERT toDATETIME.
SELECT
...
CASE WHEN DATEPART(dd,(CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME)) BETWEEN 1 AND 15
THEN CONVERT(DATETIME, CONVERT(varchar, DATEPART(yyyy,(CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME)))+ '-' + CONVERT(VARCHAR, DATEPART (mm,(CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME))) + '-' + CONVERT(VARCHAR, 15))
ELSE DATEADD(DAY, -1, CONVERT(DATETIME, CONVERT(VARCHAR, DATEPART(yyyy,(CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME)))+ '-' + CONVERT(VARCHAR, DATEPART(mm,CURRENT_TIMESTAMP + MM.IAM_MAN_LEAD_TIME)+ 1) + '-' + CONVERT(VARCHAR, 1)))
END AS 'LT_CALC'
...
Note that in the ELSE statement, the logic to get the last day of the month is to go the first day of the following month, and then use the DATEADD function to subtract one day. The SQL Server function EOMONTH , introduced in SQL Server 2012, eliminates the need for that logic.
Try this
SELECT CAST(LEFT(CONVERT(varchar, CURRENT_TIMESTAMP + LEAD_TIME, 103 ),2) as int)
then
CASE WHEN CAST(LEFT(CONVERT(varchar, CURRENT_TIMESTAMP + LEAD_TIME, 103 ),2) as int) < 15 THEN
....
ELSE
....
END

default date value of every Friday in SQL Server?

In SQL Server 2008 i want to set a default date value of every Friday to show up in the column when i insert a new record?
ALTER TABLE myTable ADD CONSTRAINT_NAME DEFAULT GETDATE() FOR myColumn
Whats the best way to show every Friday?
I want the default value to be based on the now date then knowing that the next available date is 05-07/2013
I have the following:
dateadd(d, -((datepart(weekday, getdate()) + 1 + ##DATEFIRST) % 7), getdate())
But when passing todays date, it gave me: 2013-06-28 which is actually LAST Friday!, it should be the up and coming Friday!
SELECT DATEADD(day,-3, DATEADD(week, DATEDIFF(week, 0, current_timestamp)+1, 0)) AS LastFridayDateOfWeek
Gets the last date of current week (sunday) then subtracts 3 from that to get Friday.
Replace current_timestamp if you need a different dates friday.
EDIT:
I thought about this a bit, and if the above (Friday THIS WEEK, so for Saturday it gives the previous date) does not work, you could easily use a reference date set like so:
DATEADD(DAY,7 + DATEDIFF(day,'20100109',#checkDateTime)/7*7,'20100108') as FridayRefDate
Same thing but with no hard coded Friday/Saturday in it:
DATEADD(DAY,7 + DATEDIFF(day,DATEADD(wk, DATEDIFF(wk,0,#checkDateTime),5),#checkDateTime)/7*7,DATEADD(wk, DATEDIFF(wk,0,#checkDateTime), 4))
So for 20100109 is a Friday.
SET #checkDateTime = '2012-01-14 3:34:00.000'
SELECT DATEADD(DAY,7 + DATEDIFF(day,'20100109',#checkDateTime)/7*7,'20100108') as FridayRefDate
it returns "2012/1/20"
But for SET #checkDateTime = '2012-01-13 3:34:00.000' it returns "2012/1/13"
If your current query gives you last Friday, the easiest thing to do is simply to add 7 to it:
select dateadd(d, 7-((datepart(weekday, getdate()) + 1 + ##DATEFIRST) % 7), getdate())
------------------^
SELECT CONVERT(DATE, ( CASE WHEN DATEPART(dw, GETDATE()) - 6 <= 0
THEN DATEADD(dd,
( DATEPART(dw, GETDATE()) - 6 ) * -1,
GETDATE())
ELSE DATEADD(dd, ( DATEPART(dw, GETDATE()) ) - 1,
GETDATE())
END )) AS NearestFriday
Just add 7 to the formula
SELECT DATEADD(dd,CAST(5-GETDATE() AS int)%7,GETDATE()+7)
To verify the formula:
WITH test AS (
SELECT GETDATE() AS d UNION ALL
SELECT DATEADD(dd,1,d)
FROM test WHERE d < GETDATE() + 30
)
SELECT
d AS [input],
DATEADD(dd,CAST(5-d AS int)%7,d+7) AS [output]
FROM test
To tweak the the formula, adjust the 5- and the +7

Get 2 Digit Number For The Month

I have an integer column "Month"
I would like to get 2 digit number for month.
This is what I have tried: DATEPART(mm, #Date)
It returns one digit for months January to September
I am using SQL Server 2008
Anyone has suggestion?
Function
FORMAT(date,'MM')
will do the job with two digit.
there are different ways of doing it
Using RTRIM and specifing the range:
like
SELECT RIGHT('0' + RTRIM(MONTH('12-31-2012')), 2);
Using Substring to just extract the month part after converting the date into text
like
SELECT SUBSTRING(CONVERT(nvarchar(6),getdate(), 112),5,2)
see Fiddle
There may be other ways to get this.
Pinal Dave has a nice article with some examples on how to add trailing 0s to SQL numbers.
One way is using the RIGHT function, which would make the statement something like the following:
SELECT RIGHT('00' + CAST(DATEPART(mm, #date) AS varchar(2)), 2)
Another simple trick:
SELECT CONVERT(char(2), cast('2015-01-01' as datetime), 101) -- month with 2 digits
SELECT CONVERT(char(6), cast('2015-01-01' as datetime), 112) -- year (yyyy) and month (mm)
Outputs:
01
201501
CONVERT(char(2), getdate(), 101)
Alternative to DATEPART
SELECT LEFT(CONVERT(CHAR(20), GETDATE(), 101), 2)
SQLFiddle Demo
append 0 before it by checking if the value falls between 1 and 9 by first casting it to varchar
select case when DATEPART(month, getdate()) between 1 and 9
then '0' else '' end + cast(DATEPART(month, getdate()) as varchar(2))
For me the quickest solution was
DATE_FORMAT(CURDATE(),'%m')
Simply can be used:
SELECT RIGHT('0' + CAST(MONTH(#Date) AS NVARCHAR(2)), 2)
Try:
select right ('0'+convert(nvarchar(2), DATEPART(mm, getdate())),2 )
My way of doing it is:
right('0'+right(datepart(month,[StartDate]),2),2)
The reason for the internal 'right' function is to prevent SQL from doing it as math add - which will leave us with one digit again.
SELECT REPLACE(CONVERT(varchar, MONTH(GetDate()) * 0.01), '0.', '')

Query in SQL Server 2008 not working in SQL Server 2005

DECLARE #MyDate Datetime
set #MyDate = GETDATE();
WITH cte AS
(SELECT #MyDate AS AllDates,
1 AS [count_all_days],
CASE WHEN DATENAME(dw, DATEADD(dd, - 1, #MyDate)) IN ('Saturday', 'Sunday') THEN 1 ELSE 0 END AS [count_week_days]
UNION ALL
SELECT DATEADD(dd, - [count_all_days], #MyDate),
[count_all_days] + 1,
CASE WHEN DATENAME(dw, DATEADD(dd, - [count_all_days], #MyDate)) IN ('Saturday', 'Sunday') THEN [count_week_days] + 1 ELSE [count_week_days]
END
FROM cte
WHERE [count_all_days] - [count_week_days] < 16
)
SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, AllDates))
FROM cte left join EmpLog ON AllDates = EmpLog.Date
left JOIN Holiday ON AllDates = Holiday.HolDate
WHERE DATENAME(dw, AllDates) NOT IN ('Saturday', 'Sunday')AND AllDates NOT IN (Select EmpLog.Date from EmpLog where EmpLog.EmpID = 1)and Holiday.HolDate IS NULL
This SQL query displays the current date and the previous 16 days. wherein those dates are not equal to the existing date on the HOLIDAY table and in the EMPLOG table.
My problem is this query works on SQL Server 2008 well but when I tried it on SQL Server 2005 it only displays the current date and the previous 16 days even though some days are in HOLIDAY and EMPLOG table.
Can someone help me please? thanks!
Try casting your Date variables -- you're comparing GetDate to Dates that don't necessarily have the same time:
left JOIN Holiday ON CAST(AllDates as Date) = CAST(Holiday.HolDate as Date)
Wrap that with all your dates and it should work. Take a look at this SQL Fiddle. In this example, I've only added 1 holiday, 1/21/2013 (MLK).
EDIT --
Try using convert(varchar, getdate(), 101) to CAST the date since SQL Server 2005 doesn't support the Date type.
Here is the updated SQL:
left JOIN Holiday ON convert(varchar, AllDates, 101) = convert(varchar, Holiday.HolDate, 101)
Do that on all your date conversions. Here is the updated Fiddle.
Thanks #user148298 for pointing this out.
Good luck.
There appears to be some differences between dates in 2008 and 2005. You have to set your database compatibility. See the following article:
http://msdn.microsoft.com/en-us/library/bb510680.aspx
Try changing the #MyDate initialisation to:
set #MyDate = Convert(DATETIME(CONVERT(VARCHAR(10), GETDATE(), 121) + ' 00:00:00', 121);
Explanation: By doing this you make the #MyDate as a "midnight today", instead of "today with current time". That way it would better join with your tables.
Assumption: The dates in your holiday tables are stored as "midnight"

SQL: extract date from string

There is a text field called myDate. This field can contain either 1) 'Fiscal year ending someDate' or 2) 'dateA to 'dateB'.
In situation 1), I want to set the field date1 = to someDate.
In situation 2), I want to set the field date1 = dateA and the field date2 = dateB.
All the dates (someDate, dateA, dateB) can be written as 1/1/2000, Jan 1, 2000, or January 1, 2000.
How do I go about extracting the dates from myDate and inserting them into the correct fields?
This doesn't look complicated enough to need a "proper" regular expression. Those textual dates can be parsed directly into a DATETIME type by SQL without any mucking around, as you can see by running this query:
SELECT CAST('1/1/2000' AS DATETIME), CAST('January 1, 2000' AS DATETIME), CAST('Jan 1, 2000' AS DATETIME)
To get -1 year and +1 day, just use DATEADD, e.g.
SELECT DATEADD(dd, 1, DATEADD(yy, -1, 'January 1 2000'))
...so, all you really need to do is cope with your two different cases and grab the dates out. So, something like:
SELECT
CASE
WHEN myDate LIKE 'fiscal year ending %' THEN CAST(DATEADD(dd, 1, DATEADD(yy, -1, REPLACE(myDate, 'fiscal year ending ', ''))) AS DATETIME)
ELSE CAST(LEFT(myDate, PATINDEX('% to %', myDate)) AS DATETIME)
END 'FromDate',
CASE
WHEN myDate LIKE 'fiscal year ending %' THEN CAST(REPLACE(myDate, 'fiscal year ending ', '') AS DATETIME)
ELSE CAST(SUBSTRING(myDate, PATINDEX('% to %', myDate) + 4, 100) AS DATETIME)
END 'ToDate'
FROM
...whatever
...should do the trick. I've not really tested that, but hopefully it'll give you enough of an idea to see what I'm getting at.
Note that some of the results will probably depend on the language settings of your server/database. For example, while 1/1/2000 is always going to be 1 Jan, is 3/4/2000 the third of April, or the fourth of March?