Reputation: 3360
.....
temp Varchar2 (20);
e_name Varchar2 (255);
.....
Begin
e_name := e_name || temp;
Dbms_Output.Put_Line('names: ' || e_name);
Output result
-------------
names: 'John', 'Sam', 'David', 'Sam', 'John', 'Alex'
How do I format my e_name to remove the duplicate names so that I have the output result
required result
-------------
names: 'John', 'Sam', 'David', 'Alex'
Upvotes: 1
Views: 10951
Reputation: 5792
Replace WM_CONCAT with LISTAGG - I'm running Oragle 10g, LISTAGG is 11g:
SELECT wm_concat(ename) AS employees
FROM emp_test
WHERE deptno = 20
/
Output - SMITH repeats twice:
SMITH,JONES,SCOTT,ADAMS,FORD,SMITH
SELECT wm_concat(distinct ename) AS employees
FROM emp_test
WHERE deptno = 20
/
The distinct fixes the problem:
ADAMS,FORD,JONES,SCOTT,SMITH
Upvotes: 1
Reputation: 17920
There is something called ASSOCIATIVE array,which act as Hash table in Java. We can put delimted text into a hash table, and thus can eliminate the duplicates.
We use EXISTS method of collection here, to check if the value is already present!
This is a simple to read NO SQL type of solution. So, performing one.
DECLARE
e_name VARCHAR2 (4000) := 'the text goes here';
L_TEMP_TEXT VARCHAR2(4000);
V_LOOPCOUNT NUMBER :=0;
T_WORD VARCHAR2(4000);
T_FINAL_TEXT VARCHAR2(4000) := ' ';
--Declare a DICT like a Hash table
TYPE DICT IS TABLE OF VARCHAR2(4000) INDEX BY VARCHAR(4000);
MYDICT DICT;
BEGIN
L_TEMP_TEXT := regexp_replace(e_name,'[,]+',','); -- Replace multiple consecutive commas as single
LOOP
v_LOOPCOUNT := v_LOOPCOUNT+1;
T_WORD := REGEXP_SUBSTR(e_name, '[^,]+', 1, V_LOOPCOUNT);
--In a loop we tokenize the String using comma as delimiter
EXIT WHEN T_WORD IS NULL;
IF NOT MYDICT.EXISTS(T_WORD) THEN
-- It is like a Hash Table, if not exists add to it.
MYDICT(T_WORD) := T_WORD;
T_FINAL_TEXT : T_FINAL_TEXT || ',' || T_WORD;
END;
END LOOP;
T_FINAL_TEXT := TRIM(BOTH ',' FROM TRIM(T_FINAL_TEXT));
-- Trimming the unwanted commas
DBMS_OUTPUT.PUT_LINE('after removing duplicates : ' || T_FINAL_TEXT);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(sqlerrm||chr(10)||dbms_utility.format_error_backtrace);
END;
/
Upvotes: 0
Reputation: 1456
This can be done in pure SQL, but it gets a bit messy, especially if you're pre-11gR2 listagg(). Since you're already in PL/SQL territory, here's a solution that eliminates the dups in a simple PL/SQL fashion:
declare e_name varchar2(255) := q'"'John', 'Sam', 'David', 'Sam', 'John', 'Alex'"';
new_ename varchar2(255) := substr(e_name,1,instr(e_name,'''',2));
begin
dbms_output.put_line ('e_name: ' || e_name);
for i in 1..length(e_name) - length(replace(e_name,',')) loop
if instr(new_ename,
substr(e_name,instr(e_name,', ',1,i),instr(e_name||', ',', ',1,i+1) - instr(e_name,', ',1,i))) = 0
then
new_ename := new_ename || substr(e_name,instr(e_name,', ',1,i),instr(e_name||', ',', ',1,i+1) - instr(e_name,', ',1,i));
end if;
end loop;
dbms_output.put_line ('new_ename: ' || new_ename);
end;
e_name: 'John', 'Sam', 'David', 'Sam', 'John', 'Alex'
new_ename: 'John', 'Sam', 'David', 'John', 'Alex'
Upvotes: 0
Reputation: 4538
Well you can modify your program like this
Begin
e_name := e_name || temp;
SELECT listagg ( names, ',' ) within GROUP (ORDER BY rn )
INTO e_name
FROM
(
SELECT level rn,
regexp_substr ( e_name, '[^,]+', 1, level ) names,
row_number ( ) over ( partition BY regexp_substr ( e_name, '[^,]+', 1, level ) order by level ) rnn
FROM dual
CONNECT BY regexp_substr ( e_name, '[^,]+', 1, level ) IS NOT NULL
)
WHERE rnn = 1;
Dbms_Output.Put_Line('names: ' || e_name);
The inner most query will convert the list into rows and then outer queries will filter and create the string again.
Upvotes: 1