Troubleshooting for Oracle ORA-30004 [duplicate] - sql

ORA-30004 when using SYS_CONNECT_BY_PATH function, cannot have seperator as part of the column
Action: Use another seperator which does not occur in any column
value, then retry.
Error on:
select ...
Sys_Connect_By_Path(myVariable || ':' || mySecondVariable, ' --> ') "myNewVar",
...
Works:
select ...
Sys_Connect_By_Path(myVariable || ':' || mySecondVariable, ' -> ') "myNewVar",
...
In the data we found some text like this
SomeText B--More Text
SomeText A--More Text
Since there is no '-->' or for that mater no '-->' in the data why does the first one error? The second one has a space in front and on the end.

Thats because -- is a part of --> separator but not a part of -> separator.
Even if your data value has --> this query should not error. Like below.
SQL> select Sys_Connect_By_Path('SomeText B-->More Text' || ':' || 'SomeText A-->More Text', ' --> ') "myNewVar"
from dual
connect by rownum<=3;
myNewVar
----------------------------------------------------
--> SomeText B-->More Text:SomeText A-->More Text
--> SomeText B-->More Text:SomeText A-->More Text --> SomeText B-->More Text:SomeText A-->More Text
--> SomeText B-->More Text:SomeText A-->More Text --> SomeText B-->More Text:SomeText A-->More Text --> SomeText B-->More Text:SomeText A-->More Text
The separator above is -->, notice the whitespace. This whitespace is considered as part of the separator i.e. chr(1)||chr(45)||chr(45)||chr(62)||chr(1). This entire string is not a part of your data or column value.
Where as below would error
SQL> select Sys_Connect_By_Path('SomeText B-->More Text' || ':' || 'SomeText A-->More Text', '-->') "myNewVar"
from dual
connect by rownum<=3;
ORA-30004: when using SYS_CONNECT_BY_PATH function, cannot have seperator as part of column value
30004. 00000 - "when using SYS_CONNECT_BY_PATH function, cannot have seperator as part of column value"
*Cause:
*Action: Use another seperator which does not occur in any column value,
then retry.
The separator above is -->, notice there is no whitespace i.e. chr(45)||chr(45)||chr(62). This entire string is indeed a part of your data or column value and hence the error.
And here's a solution (performance un-tested)
select regexp_replace(Sys_Connect_By_Path('SomeText B-->More Text' || ':' || 'SomeText A-->More Text', ' -> '),' -> ','-->') "myNewVar"
from dual
connect by rownum<=3;
myNewVar
--------------------------------------
-->SomeText B-->More Text:SomeText A-->More Text
-->SomeText B-->More Text:SomeText A-->More Text-->SomeText B-->More Text:SomeText A-->More Text
-->SomeText B-->More Text:SomeText A-->More Text-->SomeText B-->More Text:SomeText A-->More Text-->SomeText B-->More Text:SomeText A-->More Text
Explanation - Here(in the query above) -> (with space) is not part of the data here i.e. -->. Once the column is conected by path the regexp_replace replaces all occurences of -> with --> so this way you still get to have --> as your separator instead of ->.

Related

Create JSON from XML - JSON_AGG OUTPUT PROBLEM

I have a problem with converting XML content to JSON format (with plain oracle select statement), where more then 1 sub level of data is present in the original XML - with my code the result of level 2+ is presented as string and not as JSON_OBJECT. Please, could someone tell me, where is fault in my code or what I'm doing wrong:
source:
<envelope>
<sender>
<name>IZS</name>
<country>SU</country>
<address>LOCATION 10B</address>
<address>1000 CITY</address>
<sender_identifier>SU46794093</sender_identifier>
<sender_address>
<sender_agent>SKWWSI20XXX</sender_agent>
<sender_mailbox>SI56031098765414228</sender_mailbox>
</sender_address>
</sender>
</envelope>
transformation select statement:
WITH SAMPLE AS (SELECT XMLTYPE ('
<envelope>
<sender>
<name>IZS</name>
<country>SU</country>
<address>LOCATION 10B</address>
<address>1000 CITY</address>
<sender_identifier>SU46794093</sender_identifier>
<sender_address>
<sender_agent>SKWWSI20XXX</sender_agent>
<sender_mailbox>SI56031098765414228</sender_mailbox>
</sender_address>
</sender>
</envelope>') XMLDOC FROM DUAL)
SELECT JSON_SERIALIZE (
JSON_OBJECT (
KEY 'envelope' VALUE
JSON_OBJECTAGG (
KEY ID_LEVEL1 VALUE
CASE ID_LEVEL1
WHEN 'sender' THEN
( SELECT JSON_OBJECTAGG (
KEY ID_LEVEL2 VALUE
CASE ID_LEVEL2
WHEN 'sender_address' THEN
( SELECT JSON_OBJECTagg (KEY ID_LEVEL22 VALUE TEXT_LEVEL22)
FROM XMLTABLE ('/sender/sender_address/*'
PASSING XML_LEVEL2
COLUMNS ID_LEVEL22 VARCHAR2 (128) PATH './name()',
TEXT_LEVEL22 VARCHAR2 (128) PATH './text()'
)
)
ELSE
TEXT_LEVEL2
END)
FROM XMLTABLE ('/sender/*'
PASSING XML_LEVEL2
COLUMNS ID_LEVEL2 VARCHAR2 (1024) PATH './name()',
TEXT_LEVEL2 VARCHAR2 (1024) PATH './text()'
)
)
ELSE
'"' || TEXT_LEVEL1 || '"'
END FORMAT JSON)
) PRETTY
)JSON_DOC
FROM SAMPLE, XMLTABLE ('/envelope/*'
PASSING XMLDOC
COLUMNS ID_LEVEL1 VARCHAR2 (1024) PATH './name()',
TEXT_LEVEL1 VARCHAR2 (1024) PATH './text()',
XML_LEVEL2 XMLTYPE PATH '.'
);
wrong result:
{
"envelope" :
{
"sender" :
{
"name" : "IZS",
"country" : "SU",
"address" : "LOCATION 10B",
"address" : "1000 CITY",
"sender_identifier" : "SU46794093",
"sender_address" : "{\"sender_agent\":\"SKWWSI20XXX\",\"sender_mailbox\":\"SI56031098765414228\"}"
}
}
}
wrong part:
***"sender_address" : "{\"sender_agent\":\"SKWWSI20XXX\",\"sender_mailbox\":\"SI56031098765414228\"}"***
For the level 1 text you're wrapping the value in double-quotes and specifying format json; you aren't doing that for level 2. If you change:
ELSE
TEXT_LEVEL2
END
to:
ELSE
'"' || TEXT_LEVEL2 || '"'
END FORMAT JSON)
then the result is:
{
  "envelope" :
  {
    "sender" :
    {
      "name" : "IZS",
      "country" : "SU",
      "address" : "LOCATION 10B",
      "address" : "1000 CITY",
      "sender_identifier" : "SU46794093",
      "sender_address" :
      {
        "sender_agent" : "SKWWSI20XXX",
        "sender_mailbox" : "SI56031098765414228"
      }
    }
  }
}
fiddle
The problem is that you need kind of conditional "FORMAT JSON" in the "SELECT JSON_OBJECTAGG ( KEY ID_LEVEL2 VALUECASE ID_LEVEL2": when the ID_LEVEL2 is 'sender_address' but not in the ELSE part, but the syntax requires you put after the END of CASE, and of course this fails for the "ELSE TEXT_LEVEL2" part.

Remove special symbols from email string

I need to replace some characters in email string, exactly such actions:
lower_email = str.lower(str.split(email,'#')[0])
nopunc_email = re.sub('[!##$%^&*()-=+.,]', ' ', lower_email)
nonum_email = re.sub(r'[0-9]+', '', nopunc_email).strip()
But in SQL
I tried to use expression TRANSLATE(lower(email), 'a1_a.a-a#1-+()a ', 'a a a a'), but it didn't give me solution.
Thanks in advance!
For example:
import re
email = 'some_email.example-2021#gmail.com'
lower_email = str.lower(str.split(email,'#')[0])
nopunc_email = re.sub('[!#_#$%^&*()-=+.,]', ' ', lower_email)
nonum_email = re.sub(r'[0-9]+', '', nopunc_email).strip()
result 'some email example'
SELECT email,
TRIM(
TRANSLATE(
LOWER(SUBSTR(email, 1, INSTR(email, '#') - 1)),
'!_#$%^&*()-=+.,0123456789',
' '
)
) AS translated
FROM table_name
Which, for the sample data:
CREATE TABLE table_name (email) AS
SELECT 'some_email.example-2021#gmail.com' FROM DUAL;
Outputs:
EMAIL
TRANSLATED
some_email.example-2021#gmail.com
some email example
db<>fiddle here

DBMS_ASSERT.enquote_name() in Oracle

I have a sample code from http://phil-sqltips.blogspot.com/2015/07/beware-of-empty-partitions.html and I'd like to understand this xmlgen sql.
WITH t AS (
SELECT table_owner
, table_name
, partition_name
, TO_NUMBER (EXTRACTVALUE (XMLTYPE (DBMS_XMLGEN.getxml ('SELECT COUNT(*) AS rows_exist FROM '
|| DBMS_ASSERT.enquote_name (str => table_owner)
|| '.'
|| DBMS_ASSERT.enquote_name (str => table_name)
|| ' PARTITION ('
|| DBMS_ASSERT.enquote_name (str => partition_name)
|| ') WHERE ROWNUM <= 1'
)
)
, '/ROWSET/ROW/ROWS_EXIST'
)
) AS rows_exist
FROM all_tab_partitions
WHERE table_owner = 'WH'
AND table_name IN ('POINT_OF_SALE_FACTS')
ORDER BY table_owner
, table_name
, partition_position
)
SELECT 'ALTER TABLE '
|| DBMS_ASSERT.enquote_name (str => table_owner)
|| '.'
|| DBMS_ASSERT.enquote_name (str => table_name)
|| ' DROP PARTITION '
|| DBMS_ASSERT.enquote_name (str => partition_name)
|| ';' AS stmt
, t.*
FROM t
WHERE rows_exist = 0
;
I've found most of them except this,
DBMS_ASSERT.enquote_name (str => table_owner).
What is the syntax of arrow in (str => table_owner) inside of enquote_name?
I found this https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_assert.htm#BABDEHBC but there is no such arrow syntax, and couldn't find web sites for this syntax.
That's the named parameter syntax. Here's the relevant documentation. So str => table_name says to set the str parameter to table_name.
In this case, it isn't necessary, since str is the first parameter for DBMS_ASSERT.ENQUOTE_NAME. So you could omit it and just call DBMS_ASSERT.enquote_name(table_owner).
But in some cases it can be very useful. For example, when there are multiple optional parameters (with defaults) and you only want to specify one of them. Or when you want to clarify the purpose of a parameter by displaying the parameter name next to the value.

Parsing XML containing name space

I am having problems with parsing XML containing name-space.
This is my XML structure (snipped, with modified data):
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02 ./camt.053.001.02.xsd">
<BkToCstmrStmt>
<Stmt>
<Ntry>
<Amt Ccy="EUR">0.0</Amt>
<CdtDbtInd>CCCC</CdtDbtInd>
<Sts>BBBB</Sts>
<BookgDt>
<Dt>2011-01-01</Dt>
</BookgDt>
<ValDt>
<Dt>2011-01-01</Dt>
</ValDt>
<AcctSvcrRef>325569685ASDAS</AcctSvcrRef>
<BkTxCd>
<Prtry>
<Cd>NOTPROVIDED</Cd>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<EndToEndId>DD545454545-54545-54</EndToEndId>
<TxId>46545445G5GG54DD5S</TxId>
</Refs>
<RltdPties>
<Dbtr>
<Nm>TEST</Nm>
<PstlAdr>
<Ctry>JJ</Ctry>
<AdrLine>TEST ADD</AdrLine>
<AdrLine>TEST ADD2</AdrLine>
</PstlAdr>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>000000000000000</IBAN>
</Id>
</DbtrAcct>
<Cdtr>
<Nm>TEST NAME</Nm>
<PstlAdr>
<Ctry>JJ</Ctry>
<AdrLine>TEST ADD3</AdrLine>
<AdrLine>TEST ADD4</AdrLine>
</PstlAdr>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>22222222222222</IBAN>
</Id>
</CdtrAcct>
</RltdPties>
<Purp>
<Cd>IIII</Cd>
</Purp>
<RmtInf>
<Strd>
<CdtrRefInf>
<Ref>GG56565656565656</Ref>
</CdtrRefInf>
<AddtlRmtInf>TEST TEST 123</AddtlRmtInf>
</Strd>
</RmtInf>
<RltdDts>
<IntrBkSttlmDt>2011-01-01</IntrBkSttlmDt>
</RltdDts>
</TxDtls>
</NtryDtls>
</Ntry>
</Stmt>
</BkToCstmrStmt>
</Document>
This is the code i use that works if root element is without namespace ():
DECLARE
l_clob CLOB;
l_bfile BFILE := BFILENAME('XML_IMPORT', 'test_import.xml');
l_dest_offset INTEGER := 1;
l_src_offset INTEGER := 1;
l_bfile_csid NUMBER := 0;
l_lang_context INTEGER := 0;
l_warning INTEGER := 0;
l_xml xmltype;
BEGIN
DBMS_LOB.createtemporary (l_clob, TRUE);
DBMS_LOB.fileopen(l_bfile, DBMS_LOB.file_readonly);
DBMS_LOB.loadclobfromfile (
dest_lob => l_clob,
src_bfile => l_bfile,
amount => DBMS_LOB.lobmaxsize,
dest_offset => l_dest_offset,
src_offset => l_src_offset,
bfile_csid => l_bfile_csid ,
lang_context => l_lang_context,
warning => l_warning);
DBMS_LOB.fileclose(l_bfile);
l_xml := xmltype(l_clob);
BEGIN
FOR r IN (
SELECT ExtractValue(Value(p),'/Ntry/Amt/text()') as TEMP_COL1
,ExtractValue(Value(p),'/Ntry/Amt/#Ccy/text()') as TEMP_COL2
,ExtractValue(Value(p),'/Ntry/ValDt/Dt/text()') as TEMP_COL3
,ExtractValue(Value(p),'/Ntry/BookgDt/Dt/text()') as TEMP_COL4
FROM TABLE(XMLSequence(Extract(l_xml,'/Document/BkToCstmrStmt/Stmt/Ntry'))) p
)
LOOP
dbms_output.put_line('Some value 1: ' || r.TEMP_COL1);
dbms_output.put_line('Some value 2: ' || r.TEMP_COL2);
dbms_output.put_line('Some value 3: ' || r.TEMP_COL3);
dbms_output.put_line('Some value 4: ' || r.TEMP_COL4);
END LOOP;
END;
END;
I would like to know how to modify my code to work with name space.
Google provided few examples but so far i had no luck implementing them into my solution.
I believe you need to pass the namespace to both the Extract() and ExtractValue() functions e.g.
FOR r IN (
SELECT ExtractValue(Value(p),'/Ntry/Amt/text()', 'xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"') as TEMP_COL1
,ExtractValue(Value(p),'/Ntry/Amt/#Ccy','xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"') as TEMP_COL2
,ExtractValue(Value(p),'/Ntry/ValDt/Dt/text()','xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"') as TEMP_COL3
,ExtractValue(Value(p),'/Ntry/BookgDt/Dt/text()','xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"') as TEMP_COL4
FROM TABLE(XMLSequence(Extract(l_xml,'/Document/BkToCstmrStmt/Stmt/Ntry', 'xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02"'))) p
)
LOOP
dbms_output.put_line('Some value 1: ' || r.TEMP_COL1);
dbms_output.put_line('Some value 2: ' || r.TEMP_COL2);
dbms_output.put_line('Some value 3: ' || r.TEMP_COL3);
dbms_output.put_line('Some value 4: ' || r.TEMP_COL4);
END LOOP;
I don't think there is a way to specify a default namespace for the ExtractValue function, so my personal preference would be to do something like this instead which avoids repeatedly declaring the namespace:
FOR r IN (
SELECT p.temp_col1,
p.temp_col2,
p.temp_col3,
p.temp_col4
FROM xmltable(
--define a default namespace to be used for all values
xmlnamespaces(
DEFAULT 'urn:iso:std:iso:20022:tech:xsd:camt.053.001.02'
),
--define an xpath expression for the values you want to extract
'/Document/BkToCstmrStmt/Stmt/Ntry'
--pass the xml type in here
PASSING l_xml
--declare the columns you would like to extract and the formats they are expected to be in
COLUMNS
temp_col1 VARCHAR2(128) path '/Ntry/Amt/text()',
temp_col2 VARCHAR2(128) path '/Ntry/Amt/#Ccy',
temp_col3 VARCHAR2(128) path '/Ntry/ValDt/Dt/text()',
temp_col4 VARCHAR2(128) path '/Ntry/BookgDt/Dt/text()'
) p
)
LOOP
dbms_output.put_line('Some value 1: ' || r.temp_col1);
dbms_output.put_line('Some value 2: ' || r.temp_col2);
dbms_output.put_line('Some value 3: ' || r.temp_col3);
dbms_output.put_line('Some value 4: ' || r.temp_col4);
END LOOP;

ABAP Alv Cell size with tooltip

In my ALV I have several cells, some cells contain other icons and tooltips without content,
However when I try to put a letter in the cell, the cell takes an obscure error size in the occurrence of the tooltip text, here is my code to fill the cell.
I use the icon #SPACE\Q# to put a tooltip
This is my code :
* Si une livraison ete planifie et a ete reculee.
ELSEIF ls_plcd2-dlivr GT ls_plcd2-dlivp.
CONCATENATE '#B_SPCE\Q' text-t13 ' ' ls_plcd2-dlivr+6(2) '/' ls_plcd2-dlivr+4(2) '/' ls_plcd2-dlivr+0(4) '#M' INTO <value> RESPECTING BLANKS.
* CONCATENATE '#DENOCO\Q' text-t13 ' ' ls_plcd2-dlivr+6(2) '/' ls_plcd2-dlivr+4(2) '/' ls_plcd2-dlivr+0(4) '#' INTO <value> RESPECTING BLANKS.
ls_colcl-color-col = gc_liprc+0(1).
ls_colcl-color-int = gc_liprc+1(1).
ls_colcl-color-inv = gc_liprc+2(1).
APPEND ls_colcl TO lt_colcl.
CONCATENATE 'ls_tbxcl-' ls_plani-fldnm INTO lv_value.
ASSIGN (lv_value) TO <value>.
<value> = text-t17. " Texte Livraison reculee pour Excel
* Si une livraison ete planifie pour cette date et elle a ete avancee.
ELSEIF ls_plcd2-dlivr LT ls_plcd2-dlivp.
CONCATENATE '#B_SPCE\Q' text-t14 ' ' ls_plcd2-dlivr+6(2) '/' ls_plcd2-dlivr+4(2) '/' ls_plcd2-dlivr+0(4) '#M' INTO <value> RESPECTING BLANKS.
* CONCATENATE '#DENOCO\Q' text-t14 ' ' ls_plcd2-dlivr+6(2) '/' ls_plcd2-dlivr+4(2) '/' ls_plcd2-dlivr+0(4) '#' INTO <value> RESPECTING BLANKS.
* <value> = text-t05.
ls_colcl-color-col = gc_lipav+0(1).
ls_colcl-color-int = gc_lipav+1(1).
ls_colcl-color-inv = gc_lipav+2(1).
APPEND ls_colcl TO lt_colcl.
Screen-Copy :