Failure of implicit conversion to number in median function in Oracle - oracle

I don't understand why implicit conversion isn't working for me for the median function in Oracle. (Obviously I have plenty of ways to work around it with proper explicit conversions, but I'm wondering why it's happening at all. Am I missing something obvious or is this a bug? It just seems so unlikely to be a bug.)
I have a table with a varchar2(255 byte) column. It's nullable, but contains no nulls. All of the strings in this field are numeric.
I can do this:
select avg(this_field) from this_table
and that's fine.
I can do this:
select median(to_number(this_field)) from this_table
and that's fine too.
But I can't do this:
select median(this_field) from this_table
because I get the error "ORA-30495: The argument should be of numeric or date/datetime type."
The Oracle documentation on MEDIAN says that implicit conversion is done:
This function takes as arguments any numeric data type or any
nonnumeric data type that can be implicitly converted to a numeric
data type.
This is the exact same wording as the Oracle documentation on AVG.
And yet:
select median(to_char('1')) from dual;
ORA-30495: The argument should be of numeric or date/datetime type.
select avg(to_char('1')) from dual;
1
select median(to_number(to_char('1'))) from dual;
1
So...what's going on?

That seems to be a documentation bug (which dates back to when it was first introduced in 10gR1). I imagine whoever wrote that copied and pasted from another function like avg, and didn't take out the bits that didn't apply for median.
Some functions, like trunc() and round(), allow either data type to be passed and also allow implicit conversion of strings to numbers - but not to dates, in my testing anyway. But those tend to be listed twice in the documentation with the different argument types, and are single-row functions; off-hand I can't think of any aggregates that behave like that.
avg() can arguably do implicit conversion because everything passed in has to be convertible to a number. They could have made median() only try to implicitly convert to number like trunc(), but perhaps there was too much overhead, or some implementation reason why it was difficult, or they planned to try to convert to dates as well; or maybe it was just overlooked.
The wording of that section would still have been wrong; the first paragraph states it takes a numeric or datetime value, so for the second to only refer to numeric would be incorrect anyway. It looks like the first sentence of that second paragraph shouldn't be there, and the rest should apply to datetimes as well, at least in terms of the return type.
There's a feedback button at the bottom of the left-hand navigation panel in the docs. You can report it there, and then see if the documentation is ever updated.
Alternatively, you could raise a service request to get the behaviour changed to match the docs - though that paragraph still needs some work...

Related

Oracle In Clause not working when using Parameter

I have a Pesky SSRS report Problem where in the main query of my report has a condition that can have more than 1000 choices and when user selects all it will fail as my backend database is Oracle. I have done some research and found a solution that would work.
Solution is
re-writing the in clause something like this
(1,ColumnName) in ((1,Searchitem1),(1,SearchItem2))
this will work however when I do this
(1,ColumnName) in ((1,:assignedValue))
and pass just one value it works. But when I pass more than one value it fails and gives me ORA-01722: Invalid number error
I have tried multiple combination of the same in clause but nothing is working
any help is appreciated...
Wild guess: your :assignedValue is a comma-separated list of numbers, and Oracle tries to parse it as a single number.
Passing multiple values as a single value for an IN query is (almost) never a good idea - either you have to use string concatenation (prone to SQL injection and terrible performance), or you have to have a fixed number of arguments to IN (which generally is not what you want).
I'd suggest you
INSERT your search items into a temporary table
use a JOIN with this search table in your SELECT

OBIEE: Casting String to date then date to string

FILTER("source"."recordCount" USING "source"."snapshot_date" =
EVALUATE('TO_CHAR(%1, ''YYYYMMDD'')', TIMESTAMPADD(SQL_TSI_DAY, -7, EVALUATE('TO_DATE(%1, %2)', "source"."snapshot_date" , 'YYYYMMDD'))))
So i have this piece of code here. I know some will say "Just use the AGO function" But somehow it's causing problems because of it's connection with other tables so what I'm trying to achieve here is like a remake. The process goes this way:
The snapshot_date there is actually in varchar format and not date. So it's like "20131016" and I'm trying to change it to a date then subtract 7 days from it using the TIMESTAMPADD function and then finally returning it back to varchar to use it with FILTER.
This snippet somehow works when testing the FILTER using hardcoded values like "20131016" for example but when tested out with the code above all the row are blank. On paper, the process i assumed would happen goes lke this. "20131016" turns to a date with a format of 20131016 (yyyymmdd) and then less 7 days: 20131009 and then turned into char again "20131009" to be used in the filter.
But somehow that doesn't happen. I think the data format is not applying either to the string->date or the date->string conversion. which results to the values not getting a match at all.
Anyone have any idea what's wrong with my code?
By the way I've already tried to use CAST instead of EVALUATE or TO_TIMEDATE with the same result. Oh and this goes to the formula of the column in BMM.
Thanks
You might get some clues by looking at the SQL generated by the BI Server. I can't see any issues with your column expression, so I wouldn't limit your debugging to that alone.
A query returning nulls is often caused by incorrect levels being set (especially on logical table sources, but potentially on a measure column too). This will often result in some form of SELECT NULL FROM ... in the physical SQL.
Try this :
FILTER("source"."recordCount" USING "source"."snapshot_date" =
EVALUATE('TO_CHAR(%1, %2)', TIMESTAMPADD(SQL_TSI_DAY, -7, EVALUATE('TO_DATE(%1, %2)', TO_CHAR("source"."snapshot_date" , 'YYYYMMDD') , 'YYYYMMDD')) , 'YYYYMMDD'))

Toad for Oracle bind variables with IN clause

I have a query that looks like this:
select * from foo where id in (:ids)
where the id column is a number.
When running this in TOAD version 11.0.0.116, I want to supply a list of ids so that the resulting query is:
select * from foo where id in (1,2,3)
The simple minded approach below gives an error that 1,2,3 is not a valid floating point value. Is there a type/value combination that will let me run the desired query?
CLARIFICATION: the query as shown is how it appears in my code, and I am pasting it into TOAD for testing the results of the query with various values. To date I have simply done a text replacement of the bind variable in TOAD with the comma separated list, and this works fine but is a bit annoying for trying different lists of values. Additionally, I have several queries of this form that I test in this way, so I was looking for a less pedestrian way to enter a list of values in TOAD without modifying the query. If this is not possible, I will continue with the pedestrian approach.
As indicated by OldProgrammer, the Gerrat's answer that "You can't use comma-separated values in one bind variable" in the indicated thread correctly answers this question as well.

Split a Value in a Column with Right Function in SSIS

I need an urgent help from you guys, the thing i have a column which represent the full name of a user , now i want to split it into first and last name.
The format of the Full name is "World, hello", now the first name here is hello and last name is world.
I am using Derived Column(SSIS) and using Right Function for First Name and substring function for last name, but the result of these seems to be blank, this where even i am blank. :)
It's working for me. In general, you should provide more detail in your questions on places such as this to help others recreate and troubleshoot your issue. You did not specify whether we needed to address NULLs in this field nor do I know how you'd want to interpret it so there is room for improvement on this answer.
I started with a simple OLE DB Source and hard coded a query of "SELECT 'World, Hello' AS Name".
I created 2 Derived Column Tasks. The first one adds a column to Data Flow called FirstCommaPosition. The formula I used is FINDSTRING(Name,",", 1) If NAME is NULLable, then we will need to test for nullability prior to calling the FINDSTRING function. You'll then need to determine how you will want to store the split data in the case of NULLs. I would assume both first and last are should be NULLed but I don't know that.
There are two reasons for doing this in separate steps. The first is performance. As counter-intuitive as it sounds, doing less in a derived column results in better performance because the SSIS engine can better parallelize the operations. The other is more simple - I will need to use this value to make the first and last name split so it will be easier and less maintenance to reference a column than to copy paste a formula.
The second Derived Column is going to actually perform the split.
My FirstNameUnicode column uses this formula (FirstCommaPosition > 0) ? RTRIM(LTRIM(RIGHT(Name,FirstCommaPosition))) : "" That says "If we found a comma in the preceding step, then slice out everything from the comma's position to the end of the string and apply trim operations. If we didn't find a comma, then just return a blank string. The default string type for expressions will be the Unicode (DT_WSTR) so if that is not your need, you will need to cast the resultant into the correct string codepage (DT_STR)
My LastNameUnicode column uses this formula (FirstCommaPosition > 0) ? SUBSTRING(Name,1,FirstCommaPosition -1) : "" Similar logic as above except now I use the SUBSTRING operation instead of RIGHT. Users of the 2012 release of SSIS and beyond, rejoice fo you can use the LEFT function instead of SUBSTRING. Also note that you will need to back off 1 position to remove the comma.

Oracle empty strings

How do you guys treat empty strings with Oracle?
Statement #1: Oracle treats empty string (e.g. '') as NULL in "varchar2" fields.
Statement #2: We have a model that defines abstract 'table structure', where for we have fields, that can't be NULL, but can be "empty". This model works with various DBMS; almost everywhere, all is just fine, but not with Oracle. You just can't insert empty string into a "not null" field.
Statement #3: non-empty default value is not allowed in our case.
So, would someone be so kind to tell me - how can we resolve it?
This is why I've never understood why Oracle is so popular. They don't actually follow the SQL standard, based on a silly decision they made many years ago.
The Oracle 9i SQL Reference states (this has been there for at least three major versions):
Oracle currently treats a character value with a length of zero as null. However, this may not continue to be true in future releases, and Oracle recommends that you do not treat empty strings the same as nulls.
But they don't say what you should do. The only ways I've ever found to get around this problem are either:
have a sentinel value that cannot occur in your real data to represent NULL (e.g, "deoxyribonucleic" for a surname field and hope that the movie stars don't start giving their kids weird surnames as well as weird first names :-).
have a separate field to indicate whether the first field is valid or not, basically what a real database does with NULLs.
Are we allowed to say "Don't support Oracle until it supports the standard SQL behaviour"? It seems the least pain-laden way in many respects.
If you can't force (use) a single blank, or maybe a Unicode Zero Width Non-Break Space (U+FEFF), then you probably have to go the whole hog and use something implausible such as 32 Z's to indicate that the data should be blank but isn't because the DBMS in use is Orrible.
Empty string and NULL in Oracle are the same thing. You want to allow empty strings but disallow NULLs.
You have put a NOT NULL constraint on your table, which is the same as a not-an-empty-string constraint. If you remove that constraint, what are you losing?

Resources