XMLCAST in oracle - sql

I have a table with an xml column and trying to do sum of values in an xml tag.
Table created:
CREATE TABLE XML_TABLE6
(
XML_COL VARCHAR2(2000 BYTE)
);
Insert into XML_TABLE6
(XML_COL)
Values
('<a><b>1</b><b>2</b></a>');
COMMIT;
I am using the below select statement to return the expression in datatype "double". But i am getting the error "ORA-00905: missing keyword".
SQL query:
select XMLCast(XMLQuery('sum(a/b)' RETURNING CONTENT)
as double) from xml_table6;
Expected output: 3.0

There are some issues in the query:
You didn't specify the column you want to take as input (XML_passing_clause)
You need to explicitly cast the column to the XMLType instance to process it with XML functions.
Oracle doesn't have double data type. See numeric data types in the documentation. XMLCAST function:
The datatype argument can be of data type NUMBER, VARCHAR2, CHAR, CLOB, BLOB, REF XMLTYPE, and any of the datetime data types.
After you've fixed this issues, it works fine:
with XML_TABLE6(XML_COL) as (
select '<a><b>1</b><b>2</b></a>'
from dual
)
select xmlcast(
XMLQuery('sum(a/b)' passing xmltype(XML_COL) RETURNING CONTENT)
as binary_double
) as res
from XML_TABLE6
|RES|
|:--|
|3.0E+000|
db<>fiddle

In Oracle, the ANSI data type is double precision, not just double.
You also need to pass in the actual column value, and as that's a string, convert it to XMLType:
select
XMLCast(
XMLQuery('sum(a/b)' PASSING XMLType(xml_col) RETURNING CONTENT)
as double precision)
from xml_table6;
Or use a normal number data type:
select
XMLCast(
XMLQuery('sum(a/b)' PASSING XMLType(xml_col) RETURNING CONTENT)
as number
)
from xml_table6;
Or binary_double:
select
XMLCast(
XMLQuery('sum(a/b)' PASSING XMLType(xml_col) RETURNING CONTENT)
as binary_double
)
from xml_table6;
db<>fiddle

Related

Can I use Varchar2(32767) or Varchar2 Table in IN of sql statement

I have stored function which is returning Varchar2 (32767) and I want to use it in select statement under IN But it gives me error when i use it in Select under IN clause.
SELECT * FROM testcustomers1 where no_of_bu1 in(select myMaxLenFunc('test') from dual);
It gives me error
Error :-
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
If the return value is less than 4k it works fine but if it is greater than that it throws the above error.
Please suggest me if I use varchar2 table or Varchar2 are return in stored function how can i use it IN clause in select.
You have the right idea using a collection instead of a string in the IN clause. Then you will not run into this problem. Try something like this:
CREATE OR REPLACE TYPE strings_t IS TABLE OF VARCHAR2 (4000)
/
CREATE OR REPLACE FUNCTION strings
RETURN strings_t
AUTHID DEFINER
IS
BEGIN
RETURN strings_t ('abc', 'def', '123');
END;
/
CREATE TABLE t (s VARCHAR2 (100))
/
BEGIN
INSERT INTO t
VALUES ('abd');
INSERT INTO t
VALUES ('def');
INSERT INTO t
VALUES ('456');
COMMIT;
END;
/
SELECT *
FROM t
WHERE t.s IN (SELECT COLUMN_VALUE FROM TABLE (strings ()))
/
Your function is PL/SQL and can return a varchar2 string of more than 4000. This is illegal for SQL (if the MAX_STRING_SIZE parameter is of value STANDARD)
http://docs.oracle.com/cd/E11882_01/appdev.112/e17126/datatypes.htm
VARCHAR2 Maximum Size in PL/SQL: 32,767 bytes Maximum Size in SQL
4,000 bytes
So you need to find a way around. Since no_of_bu1 is a SQL column and cannot have more than 4000 bytes in content length you are save with this:
SELECT * FROM testcustomers1
where no_of_bu1 in(select substr(myMaxLenFunc('test'),1,4000) from dual);
Although I would truncate the string within the function.
If your DB is of Oracle 12.1 you can find out if your are STANDARD in SQL stringsize (i.e. 4000)
SELECT name, value
FROM v$parameter
WHERE name = 'max_string_size'

Difference between STRPOS(Postgres) and CHARINDEX(MSSQL) For numeric Value

Crate a table temp in both Postgres and SQL Server database.
create table temp (id numeric(10), name varchar(10));
insert into temp (id,name) values(10,'abc');
In MS SQL Server: select CHARINDEX('10',id) from temp (Success retrun 1)
In Postgres: select strpos('10',id) from temp
SQL Error [42883]: ERROR: function strpos(unknown, numeric) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
When I pass the parameter as numeric then get an error.
In SQL Server: select CHARINDEX(10,id) from temp;
SQL Error [8116] [S0001]: Argument data type int is invalid for argument 1 of charindex function.
There is a question simple that how second parameter implicitly converted to string in SQL Server, which column is numeric.
But for Postgres does not implicitly convert the value.
That's why I created a custom function but problem is same
CREATE OR REPLACE FUNCTION CHARINDEX(text, text, integer)
RETURNS integer
AS $$
SELECT CASE WHEN position(substr($2, $3+1)in $1) = 0 THEN 0 ELSE position(substr($2, $3+1)in $1) + $3 END;
$$
LANGUAGE SQL IMMUTABLE
RETURNS NULL ON NULL INPUT;
I search lots for datatype in CHARINDEX(MSSQL).
Need help for create such type of custom function which one accept all type as String.

Could not determine polymorphic type because input has type "unknown"

I have a query which gives output as
Could not determine polymorphic type because input has type "unknown"
Query :
select ( array_to_string(array_agg(name), ', '))::text as name,path
from(select 'fullpath' as Path,null as id,'' as name
from tblabc where key = 'key1' and value = '1'
) as e
group by path;
I have a postgres database
The issue here is that '' as name doesn't actually specify a type for the value. It's the unknown type, and PostgreSQL usually infers the real type from things like what column you're inserting it into or what function you pass it to.
In this case, you pass it to array_agg, which is a polymorphc function. It can take inputs of the pseudo-type anyelement, which really just means "figure it out at runtime".
PostgreSQL would still figure it out except that array_to_string doesn't actually take a text[] as input. It takes anyarray - another polymorphic type, like anyelement for arrays.
So there's nothing in the query to tell PostgreSQL what type that '' is. It could guess you meant text, but it's a bit too fussy for that. So it complains. The issue simplifies down to:
regress=> SELECT array_to_string(array_agg(''), ',');
ERROR: could not determine polymorphic type because input has type "unknown"
To solve this, write a typed literal:
TEXT '' AS name
or use a cast:
CAST('' AS text) AS name
or the PostgreSQL shorthand:
''::text
examples:
regress=> SELECT array_to_string(array_agg(TEXT ''), ',');
array_to_string
-----------------
(1 row)
regress=> SELECT array_to_string(array_agg(''::text), ',');
array_to_string
-----------------
(1 row)
regress=> SELECT array_to_string(array_agg(CAST('' AS text)), ',');
array_to_string
-----------------
(1 row)

collect function on clobs

I need to select several clobs as a nested table.
create table t (vc_val varchar2(100), clob_val clob);
create type varchar_t as table of varchar2(100);
create type clob_t as table of clob;
Following query works fine:
select cast(collect(vc_val) as varchar_t) from t;
And following fails, why?
select cast(collect(clob_val) as clob_t) from t;
Link to this example http://sqlfiddle.com/#!4/b01e7/3
Can someone explain me why second query fails?
It doesn't work because CAST doesn't support LOB types.
You can read about this in Oracle's Documentation: CAST Function In Oracle
Using your test data from SQLFiddle, CAST can convert a CLOB to a VARCHAR2:
SELECT CAST(clob_val AS VARCHAR2(100)) FROM t;
Result:
CAST(CLOB_VALASVARCHAR2(100))
-----------------------------
clob1
clob2
But we can't do it the other way around, the CLOBs are just not supported:
SELECT CAST(vc_val AS CLOB) FROM t;
> 00932. 00000 - "inconsistent datatypes: expected %s got %s"
CREATE OR REPLACE TYPE t_clob_tab as table of clob;
declare
l_clob_tab t_clob_tab;
begin
-- collect some data as clobs into a nested table
select
cast(multiset(
select to_clob(object_name)
from dba_objects
where rownum <= 10)
as t_clob_tab)
into l_clob_tab
from dual;
-- show the data
for i in 1 .. l_clob_tab.count
loop
dbms_output.put_line('Clob' || i || ' Value is: ' || l_clob_tab(i));
end loop;
end;
Output:
Clob1 Value is: C_OBJ#
Clob2 Value is: I_OBJ#
Clob3 Value is: TAB$
Clob4 Value is: CLU$
Clob5 Value is: C_TS#
Clob6 Value is: I_TS#
Clob7 Value is: C_FILE#_BLOCK#
Clob8 Value is: I_FILE#_BLOCK#
Clob9 Value is: C_USER#
Clob10 Value is: I_USER#
As for the CAST function support for LOB types:
CAST does not directly support any of the LOB data types. When you use
CAST to convert a CLOB value into a character data type or a BLOB
value into the RAW data type, the database implicitly converts the LOB
value to character or raw data and then explicitly casts the resulting
value into the target data type. If the resulting value is larger than
the target type, then the database returns an error.
This seems to refer to converting from a CLOB -> Varchar. But if you already have Clobs, you should be able to put them into a collection (a nested table in this case).
I typically use CAST + MULTISET instead of COLLECT, I think its easier and less fussy. I think your problem is with COLLECT + CAST here, not CAST itself (similar issue with NUMBER precisions).
EDIT:
I removed any suggestion of using Collect function, although I could use it without error in a simple select, I could not use it in pl/sql. Also, in addition to the CAST + MULTISET option above (SQL or pl/sql), you can (in pl/sql anyway) simply do:
select clob_col
bulk collect into l_clob_tab
from t;
Hope that helps.

SQL query for date format for CLOB field is not working

Hi I am using the below query to get the date in the format 'DD-MM-YYYY' from a CLOB field from ORACLE Toad.
Select ID, NVL(TO_CHAR(xmltype(XML_RAW).extract('//ROWSET//ROW//MJR_V//MJR_V_ROW//EARLIEST_ACCEPT_DATE/text()').getStringVal(), 'DD-MM-YYYY'),'')
AS Dateformat from table1 where ID = 102
It thorws error:
ORA:01722: Invalid number
But if I use the above query direct DB columns (NOT CLOB FIELDS) then it executes fine.
Select ID, NVL(TO_CHAR(Start_Date, 'DD-MM-YYYY'),'')
AS Dateformat from table1 where ID = 102
Please let me the solution.
You shouldn't run to_char on varchar2
to_char function gets a date (or a number) as an argument and converts it to a varchar2.
If you use it on a varchar2, then oracle implicitly converts the string to a date according to NLS_DATE_FORMAT
So you sould probably do something like this: