Conversion failed when converting date and/or time from character string in SQL - sql

I have the following columns in my table:
year decimal(4,0)
month decimal(2,0)
day decimal(2,0)
and I am trying to convert them as below:
SELECT (CAST (CAST(year AS varchar(4))
+CAST(month AS varchar(2))
+CAST(day AS varchar(2)
) AS date ) ) AS xDate
FROM table
ORDER BY xDate DESC
But I am getting this error:
Conversion failed when converting date and/or time from character string.

Your approach does not take into account that month or day can be a single-digit value. If you had a row like this:
year month day
---- ----- ---
2014 7 18
your method would concatenate the parts as 2014718 and the subsequent attempt to convert that into a date would result in the error in question.
You probably meant to combine the parts like this: 20140718, which would convert to date without issues. To me, the easiest way to get to that format from numerical parts is to go like this:
calculate year * 10000 + month * 100 + day;
convert the previous result to char(8);
convert the string to date.
So, in Transact-SQL it would be like this:
CAST(CAST(year * 10000 + month * 100 + day AS char(8)) AS date)
On a different note, I cannot possibly know whether you really need to store your dates split like that, of course, but if you do insist on doing so, at least consider using integer type(s) for the parts. I realise that decimal(2,0) may serve as some kind of constraint for you that makes sure that you cannot have month or day values with more than 2 digits, but it still does not protect you from having invalid months or days. And another major point is decimal(2,0) requires more storage space than even int, let alone smallint or tinyint.
So, this would seem fine to me
year int,
month int,
day int
but if you are into saving the storage space as much as possible, you could also try this:
year smallint,
month tinyint,
day tinyint
Finally, to make sure you cannot have invalid values in those columns, you could add a check constraint like below:
ALTER TABLE tablename
ADD CONSTRAINT CK_tablename_yearmonthday CHECK
ISDATE(CAST(year * 10000 + month * 100 + day AS char(8))) = 1
;

This issue is because you have redundant data in your table(Nothing wrong with your query). check following in your table.
1). values for days columns must not be greater than max number of days in associated month (e.g month 2 must not have 30 or 31 days in it).
2). value for month column must not be greater than 12 or equal to 0.

Related

split the date then divide it into three columns

I have a column for a date in this format 2/21/2020, and 11/2/2020
what I mean if it the month 2 it will be one digit if it is 11 two digits
the result that I need from the above examples should be like 20200221 and 20201102
so I decided to split the date and divide them into three columns be like year:2020 month:02 day:21
then I will combine them
year || month || day
now I know how to split the year
select
regexp_substr(date1, '[^/]+$', 1, 1) as year
from (select '2/11/2020' as date1 from dual)
but if I need the month or the day what I should change in the code
In addition, If the month contains one digit, the 0 should be added beside the month number like 02. do I use case when condition?
Is there any easier way to solve this problem
Try this hope you like it.
declare #TargetDate datetime='2/21/2020'
SELECT REPLACE(CONVERT(varchar,(SELECT #TargetDate),23), '-', '') as Date;
If your column is of date datatype then
To_char(your_date_column, 'yyyymmdd')
If your column is of varchar datatype then
To_char(to_date(your_date_column_in_string,'mm/dd/yyyy'), 'yyyymmdd')
Dont worry about one or two digit in day or month as oracle is smart enough to recognize it.
See this db<>fiddle demo

Get the month and year now then count the number of rows that are older then 12 months in SQL/Classic ASP

I know this one is pretty easy but I've always had a nightmare when it comes to comparing dates in SQL please can someone help me out with this, thanks.
I need to get the month and year of now then compare it to a date stored in a DB.
Time Format in the DB:
2015-08-17 11:10:14.000
I need to compare the month and year with now and if its > 12 months old I will increment a count. I just need the number of rows where this argument is true.
I assume you have a datetime field.
You can use the DATEDIFF function, which takes the kind of "crossed boundaries", the start date and the end date.
Your boundary is the month because you are only interested in year and month, not days, so you can use the month macro.
Your start time is the value stored in the table's row.
Your end time is now. You can get system time selecting SYSDATETIME function.
So, assuming your table is called mtable and the datetime object is stored in its date field, you simply have to query:
SELECT COUNT(*) FROM mtable where DATEDIFF(month, mtable.date, (SELECT SYSDATETIME())) > 12

How do I write a WHERE statement to match dates on the last day of the month?

I am querying a time series database table and I want to return data where the created_date is on the last day of the month (End of Month). The schema looks like this:
| int | varchar(12) | smalldatetime |
| primary key | data | created_date |
and the query I want to write is something like
SELECT * FROM my_table where create_date IS end_of_month
Is there a built in function for this in Sybase? If not, what would the logic be to create a query like this? Can it be done without writing a function?
I've been able to write a function to get the last day of the month for any given month. What I'm looking for now is a way to match on all given End of Months.
you can use dateadd and removeing one day DATEADD(day,-1,1stDayOfMonth)
-- Date format mm/dd/yyyy and calculate the last day of month m-1
-- example for 03/23/2015 dateadd calulate => 28/02/2015
DATEADD(day,-1, RTRIM (cast(datepart(mm,getdate()) as varchar(2)))+'/01/'+cast(datepart(yyyy,getdate()) as varchar(4)) )

How does this aggregated query find the correct values

I am having trouble understanding this code. It actually seems to work, but I don't understand how the correct value for activity year and month is "found" get the proper min and max? Or is it running all permutations getting the highest? This is very strange to me.
I do understand how the dateadd works, just not how the query is actually working on the whole. This may be a bad question since I don't actually need help solving a problem, just insight into why this works.
select
EmployeeNumber,
sum(BaseCalculation) as BaseCalculation,
min(dateadd(mm, (ActivityYear - 1900) * 12 + ActivityMonth - 1 , 0)) as StartDate,
max(dateadd(mm, (ActivityYear - 1900) * 12 + ActivityMonth - 1 , 0)) as EndDate
from
Compensation
where
1=1
-- and
group by
EmployeeNumber
for both the min and max function call, the algorithm is
dateadd(mm, (ActivityYear - 1900) * 12 + ActivityMonth - 1 , 0)
Your query compute all possible date from the Compensation table using this algorithm. Then, you select the minimum date as StartDate and the maximum as EndDate.
This is how the proper max and min are returned.
Note that the dateadd signature is DATEADD (datepart , number , date )
Since the last parameter is 0, you are addind to month(mm) the number calculated in the algorithm, and return the corresponding date starting from 0.
Check this out for more information : https://msdn.microsoft.com/en-us/library/ms186819.aspx
It is converting the columns ActivityYear and ActivityMmonth to a date. It is doing so by counting the number of months since 1900 and adding them to time zero. So, Jan 2000 would become something like Jan, 100. This seems like a very arcane calculation, because dates that are about 2,000 years old are not really useful.
Of course, this assumes that ActivityYear is a recognizable recent year.
I would convert the year and month to the first day of the beginning of the month, with something like this:
min(cast(cast(ActivityYear * 10000 + ActivityMonth + 1 as varchar(255)) as date)
Sql Server will calculate every value of that statement, and then only return the min and max.
Although I cannot say for sure that sql server executes this way internally, the way I think about it I imagine that the engine strips off the group by and all the aggregate functions, runs that query. And then just sums/finds the min etc off of that.

Returning all rows falling within a time period

I have a doubt in writing sql.
I had a farmerfields table with
YEAR,SEASON,Number of Fields.
and season look like this
Kharif---- 15june-15Oct
Rabi---15 oct to 15 Feb
Summer----15Feb to 15 June
now i want to write sql which returns all the rows excluding the current season in the current year. ie we should get the current season based on system date.
I am cracking my brain to get this, but could not.
Please help me.
I would suggest that you define a seasons table with three rows as above, e.g.
create table season (
season_id int,
description varchar(32),
start_day_of_month int,
start_month int
end_day_of_month int,
end_month int
)
the year is not included here just the day of month and month indices.
Your farmerfields table should then have a seaon_id column referring to this and most likely have a year column too.
Depending on your SQL vendor different date functions will be available but should should be able to compose a start and end date using the year from farmerfields and the month and day-of-month from season. Given this you can then determine if the current date falls within a given farmerfield entry's start and end dates.
Your table structure is wrong and not fit for what you need.
Instead of single field called SEASON, have two fields: SEASON_START and SEASON_END both of type Date then the query is as simple as:
Select * From [farmerfields] Where GetDate() Between SEASON_START And SEASON_END
If the names are part of your current SEASON field, add third field SEASON_NAME as well and the new structure will be:
SEASON_NAME | SEASON_START | SEASON_END
---------------------------------------
Kharif | 15june | 15Oct
Rabi | 15 oct | 15 Feb
...
Edit: in my above sample code I assumed you have SQL Server database - in case of different database you'll have different function to get current system date.
For difference of dates you can use the sql function DATEDIFF
SELECT * FROM table WHERE `date` BETWEEN '2011-10-20' AND '2011-1-1' AND DATEDIFF(`date`, '2011-10-20') % 10 = 0
I would suggest that you define a seasons table with three rows as above, e.g.
create table season (
season_id int,
description varchar(32),
start_day_of_month int,
start_month int
end_day_of_month int,
end_month int
)
The year is not included here just the day of month and month indices.
Your farmerfields table should then have a season_id column referring to this and most likely have a year column too.
Depending on your SQL vendor different date functions will be available but should should be able to compose a start and end date using the year from farmerfields and the month and day-of-month from season. Given this you can then determine if the current date falls within a given farmerfield entry's start and end dates.