Extract specific matching text from a string column - plsql

[The picture contains error message column(input) and err codes column (which i want the output)
I have some error codes (like 40000097,40000083 , 40000109 etc), if the error codes are there in the input text(error message) then that error code should reflect as output , if more than one error codes present then those should reflect in the output seperated by comma(,).
Please help me .. Thanks in advance ]1
create or replace function split(i_str in varchar2)
return sys.odcivarchar2list pipelined is
begin
for i in 1..length(' '||regexp_replace(i_str, '[^ ]+')) loop
pipe row (regexp_substr(i_str, '[^ ]+', 1, i));
end loop;
end;`
--using below code trying to fetch, but in the error_message if there is no space before the error_code(ie, error_message like 'lkjkkjlkjl40000097 ' then it is not identifying, if the error_message like 'lkjkkjlkjl 40000097 ') then it is identifying... please suggest me the necessary changes to be done in the below code or in the function)
select chk.*,Error_codes
from CHECK_ chk
join
(select CLAIM_NO,
listagg(t2.column_value, ',') within group (order by rn, c1, c2) Error_codes
from (select rownum rn, c1,c2,CLAIM_NO from (select CLAIM_NO,Error_Message c1,'40000109 40000083 40000098 40000101 40000076 40000097 40000088 40000081' c2 from CHECK_)) t
cross join table(split(c1)) t1
left join table(split(c2)) t2 on t2.column_value = t1.column_value
group by rn,CLAIM_NO)ss on chk.CLAIM_NO=ss.CLAIM_NO`

Related

Oracle Json object DISTINCT keep getting repeating columns

So i have a query and it need to return a JSON object but the DISTINCT doesn't work no matter what I try. I've been trying a series of other tests and no matter what the 'WBS' always shows up with 3 or more duplicated columns. Anyone got any ideas?
I am working in Asp.net 6 MVC
PROCEDURE GET_BASELINE_RPT (in_WBS_LEVEL_ID IN NUMBER, in_FISCAL_YEAR IN VARCHAR2,
in_FISCAL_MONTH IN VARCHAR2, RET OUT CLOB) AS
BEGIN
WITH cte AS (
SELECT /*+MATERIALIZE*/ DISTINCT L.WBS_LEVEL_ID
FROM
WBS_LEVEL L
)
SELECT
JSON_ARRAYAGG (
JSON_OBJECT (
'WBS' VALUE L.WBS_LEVEL_NAME,
'Title' VALUE W.DESCRIPTION,
'Rev' VALUE B.REV_NUMBER,
'ScopeStatus' VALUE W.STATUS,
'BCP' VALUE CASE WHEN BC.FISCAL_YEAR = 0 THEN '' ELSE
SUBSTR(BC.FISCAL_YEAR,3,2)||'-'||LPAD(BC.BCP_FISCAL_ID, 3, '0') END,
'BCPApprovalDate' VALUE BC.APPROVAL_DATE,
'Manager' VALUE P1.NICK_NAME,
'ProjectControlManager' VALUE P2.NICK_NAME,
'ProjectControlEngineer' VALUE P3.NICK_NAME,
'FiscalYear' VALUE W.FISCAL_YEAR,
'FiscalMonth' VALUE W.FISCAL_MONTH,
'WBSNumber' VALUE L.WBS_LEVEL_ID
)RETURNING CLOB)
INTO RET
FROM WBS_LEVEL L
LEFT OUTER JOIN BASELINE_RPT B ON L.WBS_LEVEL_ID = B.WBS_LEVEL_ID
JOIN BCP BC ON BC.BCP_ID = B.BCP_ID
LEFT OUTER JOIN WBS_TREE_MOD W ON L.WBS_LEVEL_ID = W.WBS_LEVEL_ID
LEFT OUTER JOIN VW_SITEPEOPLE P1 ON W.WBS_MANAGER_SNUMBER = P1.SNUMBER
LEFT OUTER JOIN VW_SITEPEOPLE P2 ON W.PCM_SNUMBER = P2.SNUMBER
LEFT OUTER JOIN VW_SITEPEOPLE P3 ON W.PCE_SNUMBER = P3.SNUMBER
ORDER BY L.WBS_LEVEL_NAME, B.REV_NUMBER DESC;
END GET_BASELINE_RPT;
so it turns out I wasn't getting duplicates at all. There were differences in the data but there were so many columns that had the same data that I didn't notice the differences until another review. I will try to restart my query but to be honest I may just put in a filter in my C#.

I need only one unique result in Oracle sdo_nn Update sentence ,

I need Only one unique result from tableB.Field to tableA.Field
I am using sdo operator sdo_nn, this is the code:
UPDATE table1 t1
SET t1.fieldA = (SELECT T2.fieldB,SDO_NN_DISTANCE(1) distance
FROM table1 T1, table2 T2
WHERE
(sdo_nn(t1.geometry,t2.geometry,'SDO_NUM_RES=1',1)= 'TRUE')
ORDER BY DIST
)
WHERE EXISTS(
SELECT 1
FROM table2 t2
WHERE sdo_nn(t1.geometry, t2.geometry,'SDO_NUM_RES=1',1)='TRUE'
AND(t2.cell_name = 'string1' or t2.cell_name = string2')AND t1.fieldA = NULL
);
In the select sentence of the subquery i get an error because i only use one field(t1.fieldA), but in the sentence i use the operator SDO_NN_DISTANCE(1) and the sql developer count this operator like another field. What is the correct way to write this sentence? I only use sql because i need to insert this code in vba
Thanks!!!
Obviously, you can't (simplified)
set t1.fieldA = (t2.fieldB, distance) --> you want to put two values into a single column
Therefore, get fieldB alone from the subquery which uses analytic function (row_number) to "sort" rows by sdo_nn_distance(1) desc; then get the first row's fieldB value.
Something like this (I hope I set the parenthesis right):
UPDATE table1 t1
SET t1.fieldA =
(SELECT x.fieldB --> only fieldB
FROM (SELECT T2.fieldB, --> from your subquery
SDO_NN_DISTANCE (1) distance,
ROW_NUMBER ()
OVER (ORDER BY sdo_nn_distance (1) DESC) rn
FROM table1 T1, table2 T2
WHERE (sdo_nn (t1.geometry,
t2.geometry,
'SDO_NUM_RES=1',
1) = 'TRUE')) x
WHERE rn = 1) --> where RN = 1
WHERE EXISTS
(SELECT 1
FROM table2 t2
WHERE sdo_nn (t1.geometry,
t2.geometry,
'SDO_NUM_RES=1',
1) = 'TRUE'
AND ( t2.cell_name = 'string1'
OR t2.cell_name = 'string2')
AND t1.fieldA IS NULL);

How to write an update statement for which number of updated columns is dynamic

I want to write an UPDATE statement in which the number of columns may vary for each run, based on the user choice.
Eg: DDL
CREATE TABLE "XX_MASK_REF"
( "TABLE_NAME" VARCHAR2(150 BYTE),
"COLUMN_NAME" VARCHAR2(150 BYTE),
"FLAG" VARCHAR2(2 CHAR) DEFAULT 'N'
);
A predefined set of table names and the respective column names are inserted into this table. The default value for the FLAG is set to 'N'.The user depends on his requirement will set FLAG to 'Y' which will vary for each run.
Sample data: Run 1
Table_Name Column_Name Flag
T1 C1 Y
T1 C2 Y
T1 C3 N
T2 C1 N
T2 C2 Y
Sample data: Run 2
Table_Name Column_Name Flag
T1 C1 Y
T1 C2 N
T1 C3 N
T2 C1 N
T2 C2 Y
I need an UPDATE statement which should run only for those columns to which the FLAG is set to Y group by table_name. From the dataset given above, In the Run 1, the No of columns for table T1 is 2 whereas in the Run 2 it is only one column that needs to be updated.
The update statement generated should be able to update all the records available in the table which means where clause is not required.
The values to be updated will be available in variables. I intended to use the TRANSLATE function through which the values will be passed to the column to the column to be updated.
I think something like this would help me
V_CHAR := 'Update' ||' ' ||V_TABLE_NAME||' ' || 'Set' ||' ' || V_COLUMN_NAME||'='||' ' || 'TRANSLATE('||V_COLUMN_NAME||', '1234567890','abcdefghijk')
Please advise me if i miss anything or unclear
As APC commented, your question is incomplete, It does not mention where the update values and the where clause for each table comes from.
If you are simply looking for generating update statements without where clauses to run manually after putting appropriate changes, you may use a simple select query like this
SELECT
'UPDATE '
|| table_name
|| ' SET '
||
LISTAGG(column_name
|| ' = :'
|| ROWNUM,',') WITHIN GROUP(
ORDER BY
column_name
)||';'
AS v_upd_set
FROM
xx_mask_ref
WHERE
flag = 'Y'
GROUP BY
table_name
This will display rows with bind arguments to be used for passing values while running them.
UPDATE_QUERY
-------------------------------
UPDATE T1 SET C1 = :1,C2 = :2;
UPDATE T2 SET C2 = :3;
If you don't want this solution, edit your question and provide us more details.

How to implement CASE SELECT in WHERE clause

I have two tables T1 and T2
Senario 1:
Table T1 has a Column C1 with values terminal1, terminal2, terminal3
Select C1 from T1
Terminal1
Terminal2
Terminal3
Table T2 has a Column C2 with values terminal1, terminal2
Select C2 from T2
Terminal1
Terminal2
Senario 2
Table T2 can sometimes be null
Select C2 from T2
(null)
(null)
My Output has to be
When Senario 1 Then
Terminal1
Terminal2
When Senario 2 Then
Terminal1
Terminal2
Terminal3
i.e when table T1 and T2 have common values I want only the matching values
and
when Table T2 has null values then I want all the values
from table T1
It seems that what you need is a left outer join. Outer joins allow us to conditionally join tables.
This version of your query will return STORE_TERMINAL_LOCATION for all the rows in SP_RETAIL_TRANSACTION and matching values only of SP_TEMP_LOOKUP.AIRPORT_TERMINAL.
SELECT DISTINCT A.STORE_TERMINAL_LOCATION, B.AIRPORT_TERMINAL
FROM SP_RETAIL_TRANSACTION A,
left outer join SP_TEMP_LOOKUP B
on A.STORE_TERMINAL_LOCATION = B.AIRPORT_TERMINAL
Your question needs some proper formatting and elaborate more on the problem you are facing. I assume, you need a statement, which shows what values intersect, and if they do not - show only tables A. For that clause, you need to use inner joins and case structure. For example:
select
ter."HEATHROW_TERMINAL",
case
when lok."HEATHROW_TERMINAL" is not null then
'Terminal is in both tables'
else
'Terminalis only in main table'
end terminal_state
from
test_terminal_v ter,
test_lookup_v lok
where
ter."HEATHROW_TERMINAL" = lok."HEATHROW_TERMINAL"(+)
wheres, test_terminal_v (A) has values "5","4","2","3" and test_lookup_v (B) has "4","2","3".
Hope it helps.
After comments: there are several approaches. 1) You can use temporary tables. Create one and the code is:
begin
insert into test_term_tmp
select
ter.terminal
from
test_terminal_v ter,
test_lookup_v lok
where
ter.terminal = lok.terminal;
if sql%rowcount = 0 then
insert into TEST_TERM_TMP
select
ter.terminal
from
test_terminal_v ter;
end if;
end;
or 2) use types, for example:
declare
type t_term_tab is table of number index by binary_integer;
l_term t_term_tab;
l_i number := 1;
begin
for l_rec1 in (
select
ter.terminal
from
test_terminal_v ter,
test_lookup_v lok
where
ter.terminal = lok.terminal)
loop
l_term(l_i) := l_rec1.terminal;
l_i := l_i + 1;
end loop;
if l_term.first is null then
l_i := 1;
for l_rec2 in (
select
ter.terminal
from
test_terminal_v ter)
loop
l_term(l_i) := l_rec2.terminal;
l_i := l_i + 1;
end loop;
end if;
end;
Test the performance, based on your data. Hope it helps.
Thank you Guys, I think I found the answer
select distinct T1.C1, T2.C2
from T1 ,T2
where T2.C2=T1.C1 or T2.C2 is null;
Where in my code it was
select distinct A.STORE_TERMINAL_LOCATION,B.AIRPORT_TERMINAL
from SP_RETAIL_TRANSACTION A,SP_TEMP_LOOKUP B
where B.AIRPORT_TERMINAL=A.STORE_TERMINAL_LOCATION or B.AIRPORT_TERMINAL is null;

refer to stored proc output param in macro?

Is there a way to refer to an output parameter of a stored procedure in a macro?
My stored procedure is:
CREATE PROCEDURE db.ssis_load_nextID
(IN tbl VARCHAR(30), OUT nextID SMALLINT )
BEGIN
DECLARE maxID SMALLINT;
SELECT MAX(loadID) INTO maxID
FROM db.SSIS_Load
WHERE TABLENAME = tbl
GROUP BY TABLENAME;
IF maxID IS NULL THEN
SET nextID = 1;
ELSE
SET nextID = maxID + 1;
END if;
END;
I want to refer to this result in a macro like:
CREATE MACRO db.tbSTG_m AS (
INSERT INTO db.tbProd (ID1, ID2, f1, f2, ..., fn, loadID)
SELECT ID1, ID2, f1, f2,..., fn,
CALL db.ssis_Load_nextID('tbProd',nextID)
FROM db.tbstg
; );
because running CALL db.ssis_Load_nextID('tbProd',nextID) returns the result I want in the first (only) row of the first (only) column.
I tried storing the result in a variable in the macro, but apparently, that's unsupported.
Also, I'd like to start with an empty SSIS_load table, so it creates the first row when the first table is loaded, instead of pre-populating the load table before the automated load process starts.
All help appreciated,
-Beth
fyi, We got it to work by removing the 'group by tablename' clause and embedding the sp in the macro:
CREATE MACRO db.tbSTG_m AS (
INSERT INTO db.tbProd
SELECT ID1, ID2, f1, f2, ..., fn (
SELECT ZEROIFNULL(MAX(loadID))+1
FROM db.ssis_load
WHERE TABLENAME = 'tbStg') mx
FROM db.tbSTG;
);
You can't use a stored proc for that (you would have to use a UDF not a procedure)
however you can do it in your macro
syntax may not be 100% correct.. working from memory but should get you close
I am assuming tbl is a parameter passed in correct?
basically you join to the id table and use that in your insert...
then you update the id table with the maximum freshly inserted ids
CREATE MACRO db.tbSTG_m AS (
INSERT INTO db.tbProd (ID1, ID2, f1, f2, ..., fn, loadID)
SELECT ID1, ID2, f1, f2,..., fn, MAXloadID + SUM(1) OVER(ROWS UNBOUNDED PRECEDING)
FROM db.tbstg
cross join (SELECT MAX(loadID) as MAXloadID
FROM db.SSIS_Load
WHERE TABLENAME = tbl
GROUP BY TABLENAME) as IDGEN
;
update db.SSIS_Load from (select MAX(loadID) as MAXloadID from tbl) as upid
set loadID = upid.MAXloadID
where db.SSIS_Load.TABLENAME = tbl
);

Resources