result of string concatenation is too long after using to_clob - sql

I am trying to create a table view by running the sql below
SELECT IACM1.CMNT_REAS_TYP,
TO_CLOB(LPAD (
LISTAGG (IACM1.CMNT_TXT, ' ')
WITHIN GROUP (ORDER BY IACM1.LN_NUM),
4000,
LISTAGG (IACM1.CMNT_TXT, ' ')
WITHIN GROUP (ORDER BY IACM1.LN_NUM)
))
FROM FT_T_IACM IACM1, FT_T_IACM IACM2
WHERE IACM1.ISSACT_ID = IACM2.ISSACT_ID
AND IACM1.CMNT_REAS_TYP = IACM2.CMNT_REAS_TYP
GROUP BY IACM1.cmnt_reas_typ;
But I am getting the error below
ORA-01489: result of string concatenation is too long
01489. 00000 - "result of string concatenation is too long"
*Cause: String concatenation result is more than the maximum size.
*Action: Make sure that the result is less than the maximum size.
I looked up and I found suggestions to use to_clob but it is still throwing this error. I am using oracle 11g. Thanks for the help in advance.

The longest a concatenated string in a LISTAGG can be is 4000 characters. In this query, the sum of the lengths of CMNT_TXT for one or more CMNT_REAS_TYP values appears to be more than 4000. The LISTAGG builds the string before the LPAD truncs it to 4000 characters - so the LPAD has no effect in this case. Also, the TO_CLOB has no impact because the LISTAGG goes to a varchar2 before anything else happens.
One way to fix this would be to put additional fields in your Group By if possible. If that's not an option, you might try using COLLECT instead of LISTAGG - you'll have more issues with getting datatypes to match up but it's doable.
Here's a link with some comparisons between LISTAGG and COLLECT and a little bit on how to use COLLECT: http://www.oracle-developer.net/display.php?id=515

No need to create custom function. Oracle has provided xmlagg function already to do that.
All you need is to convert the output into clob by GetClobVal and also need to rtrim as it will return delimiter in the end of the results.
SELECT RTRIM(XMLAGG(XMLELEMENT(E,colname,',').EXTRACT('//text()') ORDER BY colname).GetClobVal(),',') from tablename;

Related

Is there an equivalent to concat_ws in oracle?

I have a ton of columns I am trying to aggregate together and most of them have NULL values. I want to separate values that do appear with a ';' but I cannot find an effective way to do this in oracle. CONCAT_WS would be exactly what I need as it would not add the delimeter between NULL values, but oracle does not support this.
concat_ws(';','dx89','dx90','dx91','dx92') as diagnoses3
ORA-00904: "CONCAT_WS": invalid identifier
Using a function like this is similar but doesn't quite get me what I need as you can see the ';' on the end of the string since dx91 and dx92 are NULL values:
dx89||';'||dx90||';'||dx91||';'||dx92 as diagnoses2
I63.8;I63.9;;
Any help would be greatly appreciated!
You can use NVL2() function specific to Oracle DB together with pipe concatenation operators :
SELECT TRIM(LEADING ';'
FROM dx89||NVL2(dx90,';'||dx90,dx90)||
NVL2(dx91,';'||dx91,dx91)||
NVL2(dx92,';'||dx92,dx92)) AS "Concatenated String"
FROM t
Demo

using length function in REGEXP_REPLACE() in Postgres

I am removing that last 3 characters from the string "ABC123" using regexp_replace function in Oracle using the below statement
select REGEXP_REPLACE('ABC123','123','', LENGTH('ABC123') - 3) from dual;
The same result can be achieved in Postgres with the below statements,
select regexp_replace('ABC123','[123]', '','g')
select translate('ABC123','123', '');
Is there any way I can use the length function for replace as I have used in Oracle?
Why not simply use left()?
select left('ABC123', length('ABC123') - 3)
The same idea can be used in Oracle as well, but you need to use the substr() function. This should be more efficient in both databases.
You could also look into the trim functionality.
http://www.postgresqltutorial.com/postgresql-trim-function/
"select REGEXP_REPLACE('ABC123','123','', LENGTH('ABC123') - 3) from dual;"
would become
select ltrim('ABC123','ABC') from dual;
resulting in 123

Replace function doesn't work as expected

I'm having trouble figuring out why REPLACE() doesn't work correctly.
I'm getting a string formatted as:
RISHON_LEZION-CMTSDV4,Cable7/0/4/U1;RISHON_LEZION-CMTSDV4,Cable7/0/4/U2;RISHON_LEZION-CMTSDV4,Cable7/0/5/U0;.....
Up to 4000 characters .
Each spot of ; represent a new string(can be up to about 15 in one string). I'm splitting it by using REPLACE() - each occurence of ; replace with $ + go down a line + concat the entire string again (I have another part that is splitting down the string)
I think the length of the string is some how effecting the result, though I never heard replace has some kind of limitation about the length of the string.
SELECT REPLACE(HOT_ALERTKEY_PK, ';', '$' || CHR(13) || CHR(10) || HOT_ALERTKEY_PK || '$')
from (SELECT 'RISHON_LEZION-CMTSDV4,Cable7/0/3/U0;RISHON_LEZION-CMTSDV4,Cable7/0/3/U1;RISHON_LEZION-CMTSDV4,Cable7/0/3/U2;RISHON_LEZION-CMTSDV4,Cable7/0/4/U0;RISHON_LEZION-CMTSDV4,Cable7/0/4/U1;RISHON_LEZION-CMTSDV4,Cable7/0/4/U2;RISHON_LEZION-CMTSDV4,Cable7/0/5/U0;RISHON_LEZION-CMTSDV4,Cable7/0/5/U1;RISHON_LEZION-CMTSDV4,Cable7/0/5/U2;RISHON_LEZION-CMTSDV4,Cable7/0/7/U0;RISHON_LEZION-CMTSDV4,Cable7/0/7/U1;RISHON_LEZION-CMTSDV4,Cable7/0/7/U2;RISHON_LEZION-CMTSDV4,Cable7/0/9/U0;RISHON_LEZION-CMTSDV4,Cable7/0/9/U1;RISHON_LEZION-CMTSDV4,Cable7/0/9/U2' as hot_alertkey_pk
FROM dual)
This for some reason result in splitting the string correctly, up to cable7/0/5/U0; , and stops. If I remove one or more parts from the start of the string (up to the semicolumn is each part) then I'm getting it up to the next cables, according to how many I remove from the beggining.
Why is this happening ?
Thanks in advance.
If you wrap your sample input string within to_clob() in the inner query, and you wrap the resulting string within length() in the outer query, you will find that the result is 8127 characters. This answers your question, but only partially.
I am not sure why replace doesn't throw an error, or perhaps just truncate the result at 4000 characters. I got exactly the same result as you did in Oracle 11.2, with the result chopped off after 3503 characters. I just looked quickly at the Oracle documentation for replace() and it doesn't say what the behavior should be if the input is VARCHAR2 but the output is more than 4000 characters. It looks as though it performed as many substitutions as it could and then it stopped (the next substitution would have gone above 4000 characters).

How to determine if a variable has a special character using dual table on sql?

I'm currently trying to check if a string has a special character (value that is not 0 to 9 A to Z a to z), but the inhouse language that I'm currently using has a very limited function to do it (possible but it will take a lot of lines). but I am able to do a query on sql. Now I would like to ask if it is possible to query using the dual table on sql, My plan is to pass the string to variable and this variable will be use on my sql command. Thanks in advance.
Here is what you can use
SELECT REGEXP_INSTR('Test!ing','[^[:alnum:]]') FROM dual;
This will return a number other than 0 whenever your string has anything other than letters or numbers.
You can use TRANSLATE to remove all okay characters from the string. You get back a string containing only undesired characters - or an empty string when there are none.
select translate(
'AbcDefg1234%99.26éXYZ', -- your string
'.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
'.') from dual;
returns: %.é

How to get rightmost 10 places of a string in oracle

I am trying to fetch an id from an oracle table. It's something like TN0001234567890345. What I want is to sort the values according to the right most 10 positions (e.g. 4567890345). I am using Oracle 11g. Is there any function to cut the rightmost 10 places in Oracle SQL?
You can use SUBSTR function as:
select substr('TN0001234567890345',-10) from dual;
Output:
4567890345
codaddict's solution works if your string is known to be at least as long as the length it is to be trimmed to. However, if you could have shorter strings (e.g. trimming to last 10 characters and one of the strings to trim is 'abc') this returns null which is likely not what you want.
Thus, here's the slightly modified version that will take rightmost 10 characters regardless of length as long as they are present:
select substr(colName, -least(length(colName), 10)) from tableName;
Another way of doing it though more tedious. Use the REVERSE and SUBSTR functions as indicated below:
SELECT REVERSE(SUBSTR(REVERSE('TN0001234567890345'), 1, 10)) FROM DUAL;
The first REVERSE function will return the string 5430987654321000NT.
The SUBSTR function will read our new string 5430987654321000NT from the first character to the tenth character which will return 5430987654.
The last REVERSE function will return our original string minus the first 8 characters i.e. 4567890345
SQL> SELECT SUBSTR('00000000123456789', -10) FROM DUAL;
Result: 0123456789
Yeah this is an old post, but it popped up in the list due to someone editing it for some reason and I was appalled that a regular expression solution was not included! So here's a solution using regex_substr in the order by clause just for an exercise in futility. The regex looks at the last 10 characters in the string:
with tbl(str) as (
select 'TN0001239567890345' from dual union
select 'TN0001234567890345' from dual
)
select str
from tbl
order by to_number(regexp_substr(str, '.{10}$'));
An assumption is made that the ID part of the string is at least 10 digits.