If I run the below queries
select to_char( TO_DATE(SYSDATE-7,'DD/MM/YY') ,'year') from dual
The result is twenty seventeen
select to_char( TO_DATE(SYSDATE-7,'DD/MM/YYYY') ,'year') from dual
The result is seventeen
why don't I get twenty seventeen for the second query?
Because you are doing an unnecessary explicit conversion from string to date, which is doing an implicit conversion from date to string based on your NLS settings.
What you should be doing is just:
select to_char(sysdate - 7, 'year') from dual;
TO_CHAR(SYSDATE-7,'YEAR')
------------------------------------------
twenty seventeen
Because sysdate-7 is already a date, you should not be calling to_date() around that, with any format. As the to_date() function takes a string argument, your sysdate-7 expression has to be implicitly converted to a string first. So you are really doing:
select to_char(to_date(to_char(sysdate - 7), 'DD/MM/YYYY'), 'year') from dual;
which is using your NLS_DATE_FORMAT value for the implicit inner to_char() call, so if that is say 'DD-MON-RR' you're actually doing:
select to_char(to_date(to_char(sysdate - 7, 'DD-MON-RR'), 'DD/MM/YYYY'), 'year') from dual;
To see what's going on in there you need to see what the full generated date is, so for that I'm going to change the NLS_DATE_FORMAT for the session to show the full year:
alter session set nls_date_format = 'SYYYY-MM-DD';
select sysdate - 7 as raw_date,
to_char(sysdate - 7, 'DD-MON-RR') as implicit_string,
to_date(to_char(sysdate - 7, 'DD-MON-RR'), 'DD/MM/YY') as implcit_yy,
to_date(to_char(sysdate - 7, 'DD-MON-RR'), 'DD/MM/YYYY') as implcit_yyyy
from dual;
RAW_DATE IMPLICIT_STRING IMPLCIT_YY IMPLCIT_YYY
----------- ------------------ ----------- -----------
2017-04-30 30-APR-17 2017-04-30 0017-04-30
Notice the different years in the last two values. The documentation has a section on format model matching. The string you are implicitly creating in the middle has a 2-digit year. When you convert the string '30-APR-17' back to a date using a YY model, it 'helpfully' assumes the current century, so the date ends up as 2017. But when you convert the same string using a YYYY model it thinks you really meant the value you passed in and so doesn't assume a century - and you passed it 17, so you end up with the year 17; that is, 0017 and not 2017. (You would also have got the answer you expected using RRRR, but it is much better to stick to YYYY and actually use 4-digit years everywhere - if you actually need to use a string at all.)
Essentially: don't rely on NLS settings or implicit conversions of dates to strings or vice versa.
In this case you don't need any conversions, so use the simpler statement at the top of this answer.
you should get 2017 for second query, not for the 1 query. Other possibility is NLS settings or session, software settings.
Apart from that you have to use 'YYYY' instead of 'YY' to get 2017
Related
I have a SQLite DB with the following columns:
File, Date_created, Owner
How do I get the list of files created in the last 30 days?
I tried the following, but it didn't limit the result. The list came back with files created 2 years ago!
SELECT * FROM Table1 WHERE Date_created > (SELECT DATETIME('now', '-30 day'))
Also, not sure if it matters, but my Created_date column is in the following date format: dd/mm/yyyy hh:mm:ss
SQLite doesn't have a native datetime data type, so that comparison's going to be on text. If your records are in DD/MM/YYYY format, you'll end up with comparisons like "07/03/2020" > "2020-06-07" which make little sense.
If you opt to store your datetimes as text, you must use a format that's lexicographically orderable. A great standard format that exhibits this property (if every piece of data has the same timezone, anyway) is ISO 8601, e.g. 2020-07-07 15:04:14+0300 at the time of writing in my timezone. As an aside, even xkcd recommends ISO 8601.
If you opt to store your datetimes as numbers, you can store them as either UNIX time, or maybe, if you're feeling adventurous, as e.g. the number 20200707150414. Do remember neither of these numeric options store timezone information, if that's important to your application.
As an aside,
SELECT * FROM Table1 WHERE Date_created > DATETIME('now', '-30 day')
is enough :)
Something like this might be what you are looking for, it's something that's come up in my head, haven't tested it.
Basically you're going 30 days backwards by Date_created.
SELECT * FROM Table1
WHERE DATEDIFF(DAY, DATEADD(DAY, -30, GETDATE()), Date_created) > 0
So I've got what could be a very silly question, but for some reason my 'problem' isn't working.
It's quite simple really. One of the fields in a SSRS tablix is a due date calculated by using the SQL function DateAdd:
=DateAdd(DateInterval.Day, (Int(Fields!TMinus.Value) * 7), Parameters!StartDate.Value)
Where TMinus is a negative integer simulating weeks and StartDate being the date the activity started.
I'm calculating the same thing in VB.NET using this formula to set up the DueDate of an activity in a row cell:
Dim intTMinus As Integer = CInt(dataItem.GetDataKeyValue("TMinus").ToString)
CType(dataItem.FindControl("RlblDue"), RadLabel).Text = CDate(DateAdd(DateInterval.Day, (intTMinus * 7), dtStartDate)).ToString
The problem is that the SSRS report shows a DIFFERENT date than the Grid, even though I've used hardcoded values to attempt to find the culprit in the report.
This calculation in the report:
=DateAdd(DateInterval.Day, (Int(-40) * 7), '12/09/2016')
Shows the date: 07/12/2015 in the Grid, but 3/4/2016 on the Report
Note DateAdd arguments data types have to be DateInterval, Double, and DateTime respectively. You are passing a string '12/09/2016' for the third argument but it requires a DateTime. By the way, strings in SSRS must be surrounded with double quotes.
After fix the expression, it should be like this:
=DateAdd(DateInterval.Day, (Int(-40) * 7), CDATE("2016-09-12"))
Which returns: 07/12/2015 as your Grid in VB.
Note CDATE("2016-09-12") converts the date string in a DateTime value.
Check your parameter is set to Date/Time type.
REFERENCE
Let me know if this helps.
In Cognos 10.2.1 (FP7), I have a situation with two tables (see below), where a given transaction may be in the same "PERIOD", but what I want to do is to only give me results for transactions that have a date after the 15th of the month (i.e - the transaction may be in PERIOD 201510, and I only want transactons on/after 10/15/2015). The PERIOD is an input parameter that the user selects - I want to build the date from a portion of the PERIOD. (Before anyone complains about syntax, etc. - I've tried to simplify this as much as possible).
Given Table A:
ID varchar
PERIOD varchar
Given Table B:
ID varchar
TYPE varchar
TRANDATE timestamp2
Query1
[A.PERIOD]=?PARM1? <- this is the user selected input parameter
Query2
[B.TYPE] in ('A','B')
Then create a join from the results of Query1 and Query2 on the A.ID=B.ID to give Results1
I've tried the following (I'm keeping this as simple as I can - so I'm ONLY working with the YEAR portion of the period):
[Results1].[TRANDATE] >= concat(substring([Results1].[PERIOD],1,4),'-10-15T00:00:00.000000000')
[Results1].[TRANDATE] >= cast(concat(substring([Results1].[PERIOD],1,4),'-10-15T00:00:00.000000000'), timestamp2)
In both cases - Cognos won't validate the expression, or, if it does validate, I get a runtime error when running the report. In both cases, I get messages basically "literal does not match format string", even with the cast.
So - how can I get pieces/portions of the parameter, and slice/dice them to use as a date comparison as I mentioned above?
Given: Column [PERIOD] of type integer in the form YYYYMM, [TRANDATE] of type date/time
[TRANDATE] >= cast(cast(cast([PERIOD]/100,integer),varchar(4)) || '-' || cast(mod([PERIOD],100),varchar(2)) || '-15',date)
Given: Column [PERIOD] of type string in the form 'YYYYMM', [TRANDATE] of type date/time
[TRANDATE] >= cast(substring([PERIOD],1,4) || '-' || substring([PERIOD],5,2) || '-15',date)
The trick is that you don't have to build a full date/time string. You only have to build a string of format 'YYYY-MM-DD' in order to cast to a date type.
Ok, I got the first part of my question answered, so here's the second part. :-) In a PLSQL query, I have criteria that looks like this:
where Doc3.clinicalDate >= ml.convert_date_to_id(:DateBegin)
and Doc3.clinicalDate < ml.convert_date_to_id(:DateEnd)
Now, I don't want to use :DateEnd itself -- I want to add 1 day so that when it compares the datetime to midnight, I get midnight of the next day. Unfortunately, when I do
where Doc3.clinicalDate >= ml.convert_date_to_id(:DateBegin)
and Doc3.clinicalDate < ml.convert_date_to_id(:DateEnd + 1)
I get "ORA-06553: PLS-306: wrong number or types of arguments in call to 'CONVERT_DATE_TO_ID'". ":DateEnd + interval '1' day" gives me "ORA-30081: invalid data type for datetime/interval arithmetic" (where :DateEnd is bound to 31-MAY-2012). If I do "convert_date_to_id(add_months(:DateEnd, 1))", it works fine. Any thoughts? Thanks.
ETA: I should clarify that this is an SSRS 2008 R2 project, and DateBegin and DateEnd are defined in the report parameters as DateTime parameters. My current workaround involves setting the :DateEnd query parameter equal to the #DateEnd report parameter + 1, but I'm worried that someday I'll forget to document this properly and confuse the heck out of whomever's trying to maintain the report (and it might be me). I don't want to pass string parameters, as suggested before.
I'm thinking that the parameters being DateTime is root of the problem. Microsoft DateTime datatypes are way more granular than Oracle's in that it supports fractional seconds and Oracle DATE format does not (Oracle TIMESTAMP does however).
Since ADD_MONTHS just spits back whatever it's passed in DATE datatype (i.e. passed TIMESTAMP becomes DATE). So maybe you can convert the parameter and add the day that way:
where Doc3.clinicalDate >= ml.convert_date_to_id(:DateBegin)
and Doc3.clinicalDate < ml.convert_date_to_id(CAST(:DateEnd as DATE)+1)
Alternatively, forget about conversions and date arithmetic on the parameters and subtract a day from the second clinicalDate:
where Doc3.clinicalDate >= ml.convert_date_to_id(:DateBegin)
and Doc3.clinicalDate - 1 < ml.convert_date_to_id(:DateEnd)
Assuming that ml.convert_date_to_id takes a DATE as an input parameter rather than a VARCHAR2 that represents a date, and assuming that the :DateEnd bind variable is a VARCHAR2, you would need something like
ml.convert_date_to_id( to_date( :DateEnd, 'DD-MON-YYYY' ) + 1 )
or
ml.convert_date_to_id( to_date( :DateEnd, 'DD-MON-YYYY' ) + interval '1' day )
Use to_date to convert the value. For example:
select &date + 1 from dual
Informing to_date('29052012','ddmmyyyy') works fine
Informing '29-may-2012' gives ORA-01722: invalid number
I'm trying to do a query like this on a table with a DATETIME column.
SELECT * FROM table WHERE the_date =
2011-03-06T15:53:34.890-05:00
I have the following as an string input from an external source:
2011-03-06T15:53:34.890-05:00
I need to perform a query on my database table and extract the row which contains this same date. In my database it gets stored as a DATETIME and looks like the following:
2011-03-06 15:53:34.89
I can probably manipulate the outside input slightly ( like strip off the -5:00 ). But I can't figure out how to do a simple select with the datetime column.
I found the convert function, and style 123 seems to match my needs but I can't get it to work. Here is the link to reference about style 123
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.ase_15.0.blocks/html/blocks/blocks125.htm
I think that convert's slightly wrongly documented in that version of the docs.
Because this format always has century I think you only need use 23. Normally the 100 range for convert adds the century to the year format.
That format only goes down to seconds what's more.
If you want more you'll need to past together 2 x converts. That is, past a ymd part onto a convert(varchar, datetime-column, 14) and compare with your trimmed string. milliseconds comparison is likely to be a problem depending on where you got your big time string though because the Sybase binary stored form has a granularity of 300ms I think, so if your source string is from somewhere else it's not likely to compare. In other words - strip the milliseconds and compare as strings.
So maybe:
SELECT * FROM table WHERE convert(varchar,the_date,23) =
'2011-03-06T15:53:34'
But the convert on the column would prevent the use of an index, if that's a problem.
If you compare as datetimes then the convert is on the rhs - but you have to know what your milliseconds are in the_date. Then an index can be used.