I have a list of months formatted with the 3 letter abbreviation followed by the last 2 numbers of the year.
For example, this current month would be SEP22. I need to find a way to turn this from a varchar into a date/datetime value, pointing to the first day of the month.
So, if I have 'SEP22', I need to get the output of September 1st, 2022 as a date/datetime object.
I can find a lot of data on turning the datetime value or numeric month into the abbreviation, but not the other way around.
I know I can make a giant case statement, but I was wondering if there's an easier method to read this type of data.
Any and all help is appreciated.
EDIT: I know the data is in the current century, I know where the data comes from and when it started being collected, all of this data has been collected in or after August 2013 (AUG13).
Try this:
SELECT
CAST(
LEFT(StringDate, 3) -- e.g. SEP
+' 1 20' -- assumes 21st century
+ RIGHT(StringDate, 2) -- e.g. 22
AS DATE
) AS ActualDate
;
For SQL Server:
convert(date, '01 ' + LEFT('SEP22', 3) + ' ' + RIGHT('SEP22', 2), 6)
When SQL Server converts the date from a string with a 2-digit year, the cutoff is at 50:
declare #myMonth table (
mo varchar(5)
)
declare #i int = 0
while #i < 100
begin
set #i = #i + 1
insert #myMonth
values ('SEP' + RIGHT('0' + CAST(#i AS VARCHAR(5)), 2))
end
SELECT mo
, convert(date, '01 ' + LEFT(mo, 3) + ' ' + RIGHT(mo, 2), 6)
FROM #myMonth
For Oracle:
TO_DATE('01' || 'SEP22', 'DDMONYY')
For Oracle, all of the dates are after 2000:
CREATE TABLE MYMONTH (
MO VARCHAR2(6) NOT NULL
)
;
INSERT INTO MYMONTH (MO)
SELECT 'SEP' || SUBSTR('0' || CAST(N AS VARCHAR2(5)), -2)
FROM (
SELECT (0 + ROWNUM) N
FROM DUAL CONNECT BY ROWNUM <= 100
)
;
SELECT MO
, TO_CHAR(TO_DATE('01' || MO, 'DDMONYY'), 'MM/DD/YYYY')
FROM MYMONTH
;
Related
I have a table which one of the column is setup as nvarchar. This column is called bestBefore. So this is giving us trouble now, I am planning to change the column type to datetime, but before that, there are corrupt record as shown below :
'Mon Feb 19 23:45:59 EST 2018'
'2017-12-11 20:55:47.831'
'Mon Dec 18 18:51:54 EST 2017'
The second row is what I expect it to my new record should look like.
So I wrote something like this :-
select top 1000 CONVERT(datetime, bestBefore, 103) from
[dbo].[TestTable] order by id desc
However I got this error -'Conversion failed when converting date and/or time from character string.'
Can someone help me? If I can convert correctly, then I might able to change the column type.
I don't think that SQL Server directly supports the following format mask:
Mon Feb 19 23:45:59 EST 2018
But we can still piece together a date format which is supported. The above timestamp with the 109 format mask would appear as follows:
Feb 19 2018 23:45:59
Consider the following query:
-- replace the yourTable CTE with your actual table
WITH yourTable AS (
SELECT 'Mon Feb 19 23:45:59 EST 2018' AS col
),
cte AS (
SELECT
col,
new_col, -- a new datetime column
CONVERT(datetime,
SUBSTRING(col, 5, 3) + ' ' + SUBSTRING(col, 9, 2) + ' ' +
RIGHT(col, 4) + ' ' + SUBSTRING(col, 12, 8), 109) AS col_out
FROM yourTable
)
col col_out
1 Mon Feb 19 23:45:59 EST 2018 19.02.2018 23:45:59
Demo
To update, just use the following:
UPDATE cte
SET new_col = col_out;
Try this, Made some changes from #Tim Biegeleisen's answer.
DECLARE #bestBefore VARCHAR(50)='2017-12-11 20:55:47.831'
IF((SELECT LEFT(#bestBefore,1)) IN('S','M','T','W','F'))
BEGIN
SELECT
CONVERT(datetime,
SUBSTRING(#bestBefore, 5, 3) + ' ' + SUBSTRING(#bestBefore, 9, 2) + ' ' +
RIGHT(#bestBefore, 4) + ' ' + SUBSTRING(#bestBefore, 12, 8), 109) AS col_out
END
ELSE
BEGIN
SELECT #bestBefore
END
Hope this helps.
I am having table containing two columns one for month and other for year. Based on these two columns I want all records for that financial year. For eg. if month is 10 and year is 2014 then offcourse its financial year will be FY 01StApr14 - 31stMar15.
How do I write a SQL select query to get all the records which were created between FY 01stApr14-31stMar15 available in that table based on month and year.
M trying below query but getting error messge as 'Incorrect syntax near the keyword 'and'.'
with cte as
(
select id,iono,iomonth,ioyear,
convert(datetime,'01/'+right('00' + convert(varchar(10),iomonth,2),2)
+ '/' +convert(varchar(4),IOyear),103) as FinDate from iodetails where iono=12345
)
select month(findate),* from cte where iono=12345 and
findate between
case
when month(findate)>=4
then convert(datetime,'01/'+'04'+ '/' +convert(varchar(4),IOyear),103) and
convert(datetime,'31/'+ '03' + '/' +convert(varchar(4),IOyear+1),103)
else
convert(datetime,'01/'+'04'+ '/' +convert(varchar(4),IOyear),103) and
convert(datetime,'31/'+ '03' + '/' +convert(varchar(4),IOyear),103)
end
Try this:
SELECT *
FROM tableA
WHERE CAST((CAST(YearCol AS VARCHAR(10)) + (CAST(MonthCol AS VARCHAR(10))) AS INT)
BETWEEN CAST((CASE WHEN #V_Month BETWEEN 4 AND 12 THEN CAST((CAST(#V_Year AS VARCHAR(10)) + '04') AS INT)
WHEN #V_Month BETWEEN 1 AND 3 THEN CAST((CAST(#V_Year - 1 AS VARCHAR(10)) + '04') AS INT)
ELSE ''
END
) AS INT)
AND CAST((CASE WHEN #V_Month BETWEEN 4 AND 12 THEN CAST((CAST(#V_Year + 1 AS VARCHAR(10)) + '03') AS INT)
WHEN #V_Month BETWEEN 1 AND 3 THEN CAST((CAST(#V_Year AS VARCHAR(10)) + '03') AS INT)
ELSE ''
END
) AS INT);
If I understand your requirements correctly, you might try this:
SELECT * FROM mytable
WHERE year(dateadd(q, -1, mydate)) = 2014
This will subtract 1 quarter (3 months) from the value of mydate and extract the year. So 31 Mar 2015 becomes 31 Dec 2014 after the subtraction, which when the year is extracted is 2014.
Oops my apologies, I see that you have two columns, month and year. In that case you might try this:
SELECT * FROM mytable
WHERE year(dateadd(q, -1, cast(cast(mymonth AS char) + '/01/' + cast(myyear AS char) AS datetime))) = 2014
That is probably not the most efficient way of doing it however.
UPDATE per my comments
Here is how you might created a computed column on your table:
ALTER TABLE mytable
ADD mydate AS cast(cast(mymonth AS char) + '/01/' + cast(myyear AS char) AS datetime)
my source table column is ReportingPeriod Nvarchar(6)
delete query has to be for datas before 2 years.
this query does not work
delete from table where ReportingPeriod < year(getdate() -2) and month as 12
I need to get 201212 as result
the criteria is current year -2 and month is 12
in 2014 expected result is 201212
in 2015 expected result is 201312
I would do all of the date maths first keeping things as datetime and then convert to nvarchar at the end. Handily, CONVERT will just truncate the result if not enough space is provided, so we just provide space for the year and month and we get what we want:
select CONVERT(nvarchar(6),
DATEADD(year,DATEDIFF(year,'20010101',CURRENT_TIMESTAMP)
,'19991201')
,112)
Result:
201212
This works because we exploit the relationship between two arbitrary dates - for instance, for any date in 2001, the result we would want would be a date in december 1999 - so that's what I've used.
It's true that the above may look overly complex for this requirement, but it's possible to make a great many problems fit the DATEADD/DATEDIFF pattern with the appropriate choice of the period to use and the two arbitrary dates and the relationship between them.
You could try something like
SELECT FROM <YOUR_TABLE>
WHERE ReportingPeriod < Convert(nvarchar(4), year(getdate()) - 2) + '12'
You could cast your ReportingPeriod to a date, so 201212 would become 2012-12-01 as I assume you aren't concerned with the day of the month.
cast(left(ReportingPeriod,4) + '-'
+ RIGHT(ReportingPeriod, 2) + '-01' as datetime)
Then take the current year -2 from GETDATE() and append the month 12 and day 31 to compare these values against, which would return 2012-12-31.
cast(cast(
cast(year(getdate()) -2 as nvarchar(4))
+ '-12-31' as nvarchar(10)) as datetime)
So combining these you should be able to select all records older than 2 years, based on the month being set to 12.
select cast(left(ReportingPeriod,4) + '-'
+ RIGHT(ReportingPeriod, 2) + '-01' as datetime) ReportPeriodDate
from [YourTable]
where cast(left(ReportingPeriod,4) + '-'
+ RIGHT(ReportingPeriod, 2) + '-01' as datetime)
<= cast(cast(
cast(year(getdate()) -2 as nvarchar(4))
+ '-12-31' as nvarchar(10)) as datetime)
Then you just need to delete with this logic.
delete [YourTable]
where cast(left(ReportingPeriod,4) + '-'
+ RIGHT(ReportingPeriod, 2) + '-01' as datetime)
<= cast(cast(
cast(year(getdate()) -2 as nvarchar(4))
+ '-12-31' as nvarchar(10)) as datetime)
Demo SQL Fiddle
I want to use a date-time picker to select a date as well as the time component. The calender allows me to pick a date but there's no possibility to choose the a specific time.
I want to choose a start and end time, to select a subset out of lot of a data.
I had a similar issue in my current project. My solution is to add a field for the date (type of date/time) and a field for the time. The time field will show a drop down list containing the 24 hours text for users to select (refer to attach screenshot below).
The steps to create the dropdown list is simple:
Open the propery of the time parameter of the report
Select Available Values (refer to attached screenshot below)
Select Specify values and add values to represent the 24 hours.
Please note, you can also set the available values from a query.
In addition, the stored procedure where the report data are retrieved should convert the date and time passed from the report to datetime type to get it work. Below shows a sample:
#StartDateTime = CONVERT(datetime, convert(nvarchar, #StartDate) +
' ' + CONVERT(nvarchar(12), #starttime))
Hope it helps.
I'm sure we have all found a way around this by now, however here is my solution.
CREATE PROCEDURE [ssrs].[Params_GetTimeTable]
(
#hr_from int = 0,
#hr_to int = 24,
#min_interval int = 15
)
AS
BEGIN
-- Internal Variables
declare #hr int = #hr_from
declare #min int = 0
declare #timetable table
(
hhmm varchar(5)
)
-- Populate the #timetable
while #hr < #hr_to
begin
while #min < 60
begin
insert into #timetable(hhmm)
select
case
when #hr < 10 then '0' + cast(#hr as varchar(2)) + ':' + case when #min < 10 then '0' + cast(#min as varchar(2)) else cast(#min as varchar(2)) end
else cast(#hr as varchar(2)) + ':' + case when #min < 10 then '0' + cast(#min as varchar(2)) else cast(#min as varchar(2)) end
end
set #min = #min + #min_interval
end
set #hr = #hr + 1
set #min = 0
end
-- Add a finishing time to the output table
insert into #timetable(hhmm)
select
case
when #hr < 10 then '0' + cast(#hr as varchar(2)) + ':00'
else cast(#hr as varchar(2)) + ':00'
end
-- Return the output
select hhmm from #timetable
END
Test the result by:
EXEC [ssrs].[Params_GetTimeTable] 0, 24, 15
Output :
hhmm
00:00
00:15
00:30
00:45
01:00
01:15
...
23:00
23:15
23:30
23:45
24:00
With the standard SSRS calendar picker, after you have selected a date, you can click in the textbox and manually enter the time value next to the selected date. I know this is not very user intuitive, but it does work.
I have the same problem, and am looking for a more user friendly solution, but this is all I can come with so far.
I use this SQL which generates times every 15mins between 9:00 and 21:00, people is just any table with at least enough rows i.e. 12 or 24.
select time1
from
(
select hr || ':' || mm time1
from
(
select '09' hr
from dual
union
select cast(rownum + 9 as varchar(2)) hr
from people
where rownum < 12
order by hr
)hr,
(
select '00' mm
from dual
union
select '15' mm
from dual
union
select '30' mm
from dual
union
select '45' mm
from dual
)mm
union
(
select '21:00' time1
from dual
)
)T1
order by time1
I use this as an integer parameter then you can add the number of minutes to whatever date is selected
DECLARE #interval INT = 15
;WITH cteM AS (
SELECT 0 M UNION ALL
SELECT M+#interval FROM cteM
WHERE M+#interval <= 59
),
cteH AS (
SELECT 0 H UNION ALL
SELECT H+1 FROM cteH
WHERE H+1 < 24
)
SELECT
RIGHT('0' + CAST(cteH.H AS varchar(2)), 2) + ':' + RIGHT('0' + CAST(cteM.M AS varchar(2)), 2) Label,
cteH.H*60 + cteM.M Value
FROM cteM CROSS JOIN cteH
I would like select data between two date, without day
An input example:
start month: 9 , start year: 2011
end month: 3, end year: 2012
I think that there are two way to do this.
The first is convert start month and start year to date like 2011-09-01 and convert last date to 2012-03-31, but this requires calculation of the last day of end month. Obtained these date we can use a BEETWEN function for the WHERE clause (but, is the CONVERT function reliable?)
The second solution is to use the DATEPART function like in the following code:
I try to explain: if end year is equal to the initial year, then month must be between the start and end months; else if the final months is greater than the initial years if different from the initial and final year, I take everything in between; else if the final year, the month must be less than or equal to the final month, if the initial year, month must be greater than or equal to the final month
Can you help me do this in the best way? Is correct, the solution I adopted?
declare #IndDebitoCredito bit,#ProgTributo int,#mi as integer,#ai as integer,#mf as integer,#af as integer,#IDAnagrafica varchar(5)
select #mi = 01,#ai = 2011,#mf = 12,#af = 2011,#IDAnagrafica = 'DELEL',#IndDebitoCredito = 1
select distinct rrd.IDTributo
from TBWH_Delega d
--inner join TBWH_SezioneDelega sd on d.IDDelega = sd.IDDelega
inner join TBWH_Rigo rd on rd.IDDelega = d.IDDelega
inner join TBWH_RataRigo rrd on rrd.IDRigo = rd.IDRigo
where
(
DATEPART(MM,d.DataDelega)<=#mf and
DATEPART(MM,d.DataDelega)>=#mi and
DATEPART(YYYY,d.DataDelega)=#ai and
#af = #ai
)
OR
(
--anno finale magg. anno iniziale
#af > #ai AND
(
( -- delega nell'intervallo
DATEPART(YYYY,d.DataDelega)<#af AND
DATEPART(YYYY,d.DataDelega)>#ai
-- DATEPART(MM,d.DataDelega)>=#mi
)
OR
( -- delega limite destro
DATEPART(YYYY,d.DataDelega)=#af AND
DATEPART(MM,d.DataDelega)<=#mf
)
OR
( -- delega limite sinistro
DATEPART(YYYY,d.DataDelega)=#ai AND
DATEPART(MM,d.DataDelega)>=#mi
)
)
)
GO
Your first solution is almost there, but is more complicated than it needs to be and won't work anyway. It will miss out any rows from the last day of the end month.
You can add one month to the end month and then use BETWEEN on the first of each month. eg.
start month: 9 , start year: 2011
end month: 3, end year: 2012
BETWEEN '2011-09-01' AND '2012-04-01'
or, as JNK points out, this will be better:
DataDelega >= '2011-09-01' AND DataDelega < '2012-04-01'
You'll need to add in some logic to deal with the end month being December, but this looks like the simplest way of doing it.
You are WAY overcomplicating this. You really only need two comparisons:
Is the month and year after or equal to the initial value?
Is the month and year before or equal to the final value?
Try:
SELECT *
FROM MyTable
WHERE Datefield BETWEEN
CAST(#mi as varchar) + '/1/' + CAST(#ai as varchar)
-- first of first month
AND
DATEADD(DAY, -1, (DATEADD(Month, + 1, (CAST(#mf as varchar) + '/1/' + CAST(#af as varchar)))))
-- Last day or final month
SELECT *
FROM Table
WHERE DateField
BETWEEN CONVERT(DATE, CONVERT(CHAR(4), #ai) + RIGHT('00' + CONVERT(VARCHAR(2), #mi), 2) + '01', 112)
AND DATEADD(DD, -1, DATEADD(MM, 1, CONVERT(DATE, CONVERT(CHAR(4), #af) + RIGHT('00' + CONVERT(VARCHAR(2), #mf), 2) + '01', 112)))
Avoid using expressions on the DateField columns, as it makes query not SARGable.
I would use:
WHERE DateToCheck >= --- first day of StartMonth
DATEADD( mm, #StartMonth-1,
DATEADD( yy, #StartYear-2000, '2000-01-01')
)
AND DateToCheck < --- first day of next month (after EndMonth)
DATEADD( mm, #EndMonth,
DATEADD( yy, #EndYear-2000, '2000-01-01')
)
DECLARE #mi INT
, #ai INT
, #mf INT
, #af INT
SELECT #mi = 01
, #ai = 2011
, #mf = 12
, #af = 2011
--local variables to hold dates
DECLARE #i DATETIME
, #f DATETIME
--build strings to represent dates in YYYYMMDD format
--add a month to the #f date
SELECT #i = CONVERT(VARCHAR(4), #ai) + RIGHT('0' + CONVERT(VARCHAR(2), #mi),
2) + '01'
, #f = DATEADD(month, 1,
CONVERT(VARCHAR(4), #af) + RIGHT('0'
+ CONVERT(VARCHAR(2), #mf),
2) + '01')
--select data where date >= #i, and < #f
SELECT *
FROM MyTable
WHERE DateField >= #i
AND DateField < #f