How to match specific pattern from a string - sql

I had return a program it will check which file is present or not and it will check no of column
create or replace procedure chkcsvfile
(P_UTLDIR VARCHAR2,
P_FILENAME VARCHAR2,
P_tabnam VARCHAR2
)
is
P_fieldel varchar2(2):= ',';
V1 VARCHAR2(32767) ;
P_errlen number :=0;
lv_a number;
lv_b number;
lv_c number;
lv_d number;
lv_check_file_exist boolean;
v_file utl_file.file_type;
cursor c1 is
select count(*) from user_tables where TABLE_NAME =P_tabnam;
cursor c2 is
select count(*) from user_tab_columns where TABLE_NAME =P_tabnam;
begin
open c1;
fetch c1 into lv_c;
if lv_c = 0 then
dbms_output.put_line('table name is invalid : ' || P_tabnam);
end if;
--'test wheather file is available or not'
dbms_output.put_line ('test wheather file is available or not');
utl_file.fgetattr (P_UTLDIR,P_FILENAME, lv_check_file_exist, lv_a, lv_b );
if lv_check_file_exist then
dbms_output.put_line('file ' ||P_FILENAME ||' exists');
v_file := utl_file.fopen(P_UTLDIR,P_FILENAME, 'R');
UTL_FILE.get_line (v_file ,V1,32767);
DBMS_OUTPUT.put_line ('V1 :' || V1);
if (REGEXP_like (V1, ',',1))
then
P_errlen := P_errlen +1 ;
dbms_output.put_line ('errrooooooooooooooooooooooooooooooooooorr');
dbms_output.put_line (P_errlen );
end if;
end if;
if not lv_check_file_exist then
dbms_output.put_line('file ' || P_FILENAME ||' does not exist');
end if;
if lv_check_file_exist is null then
dbms_output.put_line('file check null');
end if;
if lv_check_file_exist is not null then
dbms_output.put_line('file check not null');
end if;
dbms_output.put_line('lv_a-->'||lv_a);
dbms_output.put_line('lv_b-->'||lv_b);
open c2;
fetch c2 into lv_d;
dbms_output.put_line ('No of columns in a table : ' || lv_d );
end;
/
NOW my problem is i have to match " , " in a string and i want the count of it . i had written the program but it not give me specific count .
data in string is given in below format
7839,KING ,PRESIDENT,0000,17-nov-1981, 005000.00 ,000000.00,10,
please help me
thanks in advance

Since you're using 11g, you can use the regexp_count function.
select regexp_count('7839,KING ,PRESIDENT,0000,17-nov-1981, 005000.00 ,000000.00,10,',',')
from dual

Related

PL/SQL Dynamic SQL : Table name not valid

I'm currently learning PL/SQL. I need to create a PL/SQL block to create a backup of all my tables like this : myTable -> myTable_old.
Here's what I got right now :
DECLARE
Cursor c IS SELECT table_name
FROM user_tables
WHERE table_name NOT LIKE '%_old';
sql_slc VARCHAR2(200);
sql_drp VARCHAR2(200);
sql_crt VARCHAR2(200);
row_count NUMBER;
t_name user_tables.table_name%type;
t_backup_name user_tables.table_name%type;
BEGIN
sql_drp := 'DROP TABLE :1 CASCADE';
sql_crt := 'CREATE TABLE :1 AS SELECT * FROM :2';
sql_slc := 'SELECT COUNT(*) FROM user_tables WHERE table_name = :1';
OPEN c;
LOOP
FETCH c INTO t_name;
EXIT WHEN (c%NOTFOUND);
t_backup_name := t_name || '_old';
dbms_output.put_line(t_name || ' ' || t_backup_name);
EXECUTE IMMEDIATE sql_slc INTO row_count USING t_backup_name;
IF row_count > 0 THEN
dbms_output.put_line(t_backup_name || ' dropped');
EXECUTE IMMEDIATE sql_drp USING t_backup_name;
END IF;
dbms_output.put_line(t_backup_name || ' created');
EXECUTE IMMEDIATE sql_crt USING t_backup_name, t_name;
COMMIT;
END LOOP;
CLOSE c;
END;
/
Here's the error :
OUVRAGE OUVRAGE_old
OUVRAGE_old created
DECLARE
*
ERROR on line 1 :
ORA-00903: table name not valid
ORA-06512: on line 29
I don't understand why this error is coming up, can someone help me ?
The issue is that you can not use bind variables for table names; Oracle documentation:
The database uses the values of bind variables exclusively and does
not interpret their contents in any way.
You should edit your code to use concatenation instead:
DECLARE
Cursor c IS SELECT table_name
FROM user_tables
WHERE table_name NOT LIKE '%_OLD'; /* OLD, upper case */
sql_slc VARCHAR2(200);
--sql_drp VARCHAR2(200);
--sql_crt VARCHAR2(200);
row_count NUMBER;
t_name user_tables.table_name%type;
t_backup_name user_tables.table_name%type;
BEGIN
-- sql_drp := 'DROP TABLE :1 CASCADE';
-- sql_crt := 'CREATE TABLE :1 AS SELECT * FROM :2';
sql_slc := 'SELECT COUNT(*) FROM user_tables WHERE table_name = :1';
OPEN c;
LOOP
FETCH c INTO t_name;
EXIT WHEN (c%NOTFOUND);
t_backup_name := t_name || '_OLD'; /* OLD, upper case */
DBMS_OUTPUT.put_line (t_name || ' ' || t_backup_name);
EXECUTE IMMEDIATE sql_slc INTO row_count USING t_backup_name;
IF row_count > 0
THEN
DBMS_OUTPUT.put_line (t_backup_name || ' dropped');
-- EXECUTE IMMEDIATE sql_drp USING t_backup_name;
EXECUTE IMMEDIATE ' drop table ' || t_backup_name; /* concatenation and not bind variables */
END IF;
DBMS_OUTPUT.put_line (t_backup_name || ' created'); /* concatenation and not bind variables */
-- EXECUTE IMMEDIATE sql_crt USING t_backup_name, t_name;
EXECUTE IMMEDIATE 'create table ' || t_backup_name || ' as select * from ' || t_name;
COMMIT;
END LOOP;
CLOSE c;
END;
Also, notice that, if not double quoted, object names always are uppercase, so you have to look for t_name || '_OLD' and not t_name || '_old'

Output of Duplicats using a Procedure

i am in the middle of studys and currently doing some exercises.
I am trying to make procedure that shows how many duplicats are in a row.
CREATE OR REPLACE PROCEDURE anzahl1(
tabelle VARCHAR2,
reihe VARCHAR2,
wieviel OUT NUMBER
)AS
test VARCHAR2(4000);
BEGIN
EXECUTE IMMEDIATE 'SELECT
reihe,
(COUNT(*)-1) AS Anzahl
INTO
wieviel
FROM
tabelle
GROUP BY
reihe
HAVING COUNT(*) > 1' using out wieviel;
DBMS_OUTPUT.PUT_LINE(wieviel);
END;
/
i tried many things but nothing worked...
even the result i was given by a teacher of my old school didnt work:
CREATE OR REPLACE PROCEDURE check_doppelte_Werte_p (
p_tabellenname IN USER_TAB_COLUMNS.TABLE_NAME%TYPE,
p_spaltenname IN USER_TAB_COLUMNS.COLUMN_NAME%TYPE,
p_ergebnis BOOLEAN
) OUT
IS
v_dummy NUMBER := 1;
v_sql_anweisung varchar2 (4000);
BEGIN
v_sql_anweisung :=
'SELECT MAX(COUNT ('
|| p_spaltenname
|| ')) '
|| ' FROM '
|| p_tabellenname
|| ' GROUP BY '
|| p_spaltenname;
DBMS_OUTPUT.PUT_LINE (v_sql_anweisung);
EXECUTE IMMEDIATE v_sql_anweisung INTO v_dummy;
IF v_dummy > 1 THEN
DBMS_OUTPUT.PUT_LINE( 'Die Tabelle '
|| 'hat mindestens '
|| TO_CHAR (V_DUMMY)
|| ' doppelte Werte in der Spalte '
|| p_spaltenname);
p_ergebnis := TRUE;
ELSE
p_ergebnis := FALSE;
END IF;
EXCEPTION
-- Keine Werte gefunden, da
WHEN NO_DATA_FOUND
THEN
p_ergebnis := FALSE;
DBMS_OUTPUT.PUT_LINE ('Tabellenname oder Spaltenname sind nicht vorhan-
den!!!');
END;
What would you do/change?
Your code doesn't substitute the variables in the dynamic sql.The query String has been to be appended with the input variables.
Please try the code below,
CREATE OR REPLACE PROCEDURE anzahl1(
tabelle VARCHAR2,
reihe VARCHAR2,
wieviel OUT NUMBER
)AS
test VARCHAR2(4000);
lv_query VARCHAR2(4000);
BEGIN
lv_query := 'SELECT (COUNT(*)-1) cnt FROM '||tabelle ||' GROUP BY '||reihe||' HAVING COUNT(*) > 1';
EXECUTE IMMEDIATE lv_query into wieviel;
DBMS_OUTPUT.PUT_LINE(wieviel);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR '||SQLCODE||' '||SUBSTR(SQLERRM,1,200));
END;
/
I create table and populate records as below,
CREATE TABLE EMP(ID NUMBER(10),NAME VARCHAR2(40));
INSERT INTO EMP VALUES (1, 'TEST');
INSERT INTO EMP VALUES (1, 'TEST');
INSERT INTO EMP VALUES (2, 'TEST2');
Now i call the stored procedure to test for EMP table for ID column,
declare
lv_cnt number(10);
begin
anzahl1('EMP','ID',lv_cnt);
dbms_output.put_line(lv_cnt);
end;
This give output as ,
1

Generate dynamic SQL query with multiple filter option(from application)added in single CLOB - Oracle

There is application in which filter option includes start date, end date, postcode, etc where user can select multiple option from single filter. Ex: User can select 5 different start date, end date and 3 different postcode or can select 1 start date, end date and no postcode. There are 7 other filters and each filter user can select multiple options. (Consider E-Commerce website like Amazon. If you want to buy mobile, you use filter for camera range like 16MP,32MP,48MP and company like 'Samsung','Motorola', 'Nokia' and similarly for processor and screen size as well. So as a developer you want to store all the value in CLOB and give the result)
Input will come something like
<date>
<start_date>01/01/2019</start_date>
<end_date>31/01/2019</end_date>
<start_date>01/03/2019</start_date>
<end_date>31/03/2019</end_date>
<start_date>01/05/2019</start_date>
<end_date>31/05/2019</end_date>
</date>
<pc>
<postcode>56012</postcode>
<postcode>56000</postcode>
<postcode>56234</postcode>
</pc>
Now my query should look something like
select col1,col2,col3 from table_name where between start_date and end_date and between start_date and end_date... and postcode like '56012' and postcode like '56000'
Result set retruned should again be sent in clob.
Is there any way out to solve this problem?
create or replace procedure get_data(p_filter IN clob, p_result clob)
is
v_query clob;
V_condition clob;
v_lp_cnt integer;
v_result clob;
v_where_clause clob;
begin
--Considering output will be returned in XML
v_query := 'SELECT XMLELEMENT (
"data", XMLAGG
(XMLELEMENT
(
"whole_data",
XMLELEMENT ("final_date", final_date),
......... from table_name where col2='xyz'';
--Considering that filter values will be less than 1000
--date
V_condition := NULL;
v_lp_cnt := 0;
FOR crec IN(SELECT t.start_date, t.end_date
FROM XMLTABLE('/Filter/final_date/Date'
PASSING xmltype(p_filter)
COLUMNS
start_date VARCHAR2(240) PATH 'Start_Date',
end_date VARCHAR2(240) PATH 'End_Date')t
WHERE 1 = 1
)
loop
v_lp_cnt := v_lp_cnt +1;
IF v_lp_cnt =1
THEN
v_condition := ' AND (ext.final_date between to_date('''|| crec.start_date ||''',''dd/mm/yyyy'') and to_date('''|| crec.end_date ||''',''dd/mm/yyyy'')';
v_where_clause := v_where_clause||v_condition;
v_condition:= null;
ELSIF (v_lp_cnt >1 and v_lp_cnt <1000)
THEN
v_condition := ' OR ext.final_date between to_date('''|| crec.start_date ||''',''dd/mm/yyyy'') and to_date('''|| crec.end_date ||''',''dd/mm/yyyy'')';
v_where_clause := v_where_clause||v_condition;
end if;
end loop;
IF v_lp_cnt>0
THEN
v_where_clause := v_where_clause|| ')';
END IF;
--postcode
v_condition := NULL;
v_lp_cnt := 0;
FOR crec IN(SELECT (t.postcode) postcode
FROM XMLTABLE('/Filter/pc/postcode'
PASSING xmltype(p_filter)
COLUMNS postcode VARCHAR2(30)PATH '/postcode')t
WHERE 1 = 1
)
loop
v_lp_cnt := v_lp_cnt + 1;
IF v_lp_cnt = 1 THEN
v_condition := ' AND (postcode in ('''|| crec.postcode ||'''';
v_where_clause := v_where_clause||v_condition;
v_condition := NULL;
ELSE
v_condition := v_condition||','||''''|| crec.postcode ||'''';
v_where_clause := v_where_clause||v_condition;
v_condition := NULL;
END IF;
END LOOP;
IF v_lp_cnt >0
THEN
v_where_clause := v_where_clause||v_condition||'))';
end if;
v_query := v_query || v_where_clause;
execute immediate v_query into v_result;
p_result := v_result;
end;

Oracle procedure cursor loop errors

Can you tell me what is wrong with this procedure that I'm trying to create?
CREATE OR REPLACE PROCEDURE create_audit_tables (table_owner VARCHAR2)
IS
CURSOR c_tables (
table_owner VARCHAR2)
IS
SELECT ot.owner AS owner, ot.table_name AS table_name
FROM all_tables ot
WHERE ot.owner = table_owner
AND ot.table_name NOT LIKE 'AUDIT_%'
AND ot.table_name <> 'EXAUDIT'
AND NOT EXISTS
(SELECT 1
FROM EXAUDIT efa
WHERE ot.table_name = efa.tname)
AND NOT EXISTS
(SELECT 1
FROM all_tables at
WHERE at.table_name = 'AUDIT_'||ot.table_name);
v_sql VARCHAR2 (8000);
v_count NUMBER := 0;
v_aud VARCHAR2 (30);
BEGIN
FOR r_table IN c_tables (table_owner)
LOOP
BEGIN
v_aud := 'AUDIT_'||r_table.table_name;
v_sql :=
'create table '
|| v_aud
|| ' as select * from '
|| r_table.owner
|| '.'
|| r_table.table_name
|| ' where 1 = 1';
DBMS_OUTPUT.put_line ('Info: ' || v_sql);
EXECUTE IMMEDIATE v_sql;
v_sql :=
'alter table '
|| v_aud
|| ' add ( AUDIT_ACTION char(1), AUDIT_BY varchar2(50), AUDIT_AT TIMESTAMP)';
EXECUTE IMMEDIATE v_sql;
v_count := c_tables%ROWCOUNT;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
'Failed to create table '
|| v_aud
|| ' due to '
|| SQLERRM);
END;
END LOOP;
IF v_count = 0
THEN
DBMS_OUTPUT.put_line ('No audit tables created');
ELSE
DBMS_OUTPUT.put_line (v_count || ' audit tables created.');
END IF;
END;
/
I checked it with show errors function and it gave me this:
LINE/COL ERROR
-------- --------------------------------------------
6/1 PL/SQL: SQL Statement ignored
16/3 PL/SQL: ORA-00906: missing left parenthesis
Perhaps the problem is quite simple, but I can't see it, so please help me if you can
I can compile procedure without problems after creating table
create table EXAUDIT (tname varchar2(100));
Check status of procedure:
select status from user_objects where lower(object_name) = 'create_audit_tables';

Any alternatives to using cursor in SQL procedure in Oracle 10g?

I give the SQL few inputs and I need to get all the ID's and their count that doesn't satisfy the required criteria.
I would like to know if there are there any alternatives to using cursor.
DECLARE
v_count INTEGER;
v_output VARCHAR2 (1000);
pc table1%ROWTYPE;
unmarked_ids EXCEPTION;
dynamic_sql VARCHAR (5000);
cur SYS_REFCURSOR;
id pp.id%TYPE;
pos INTEGER;
BEGIN
v_count := 0;
SELECT *
INTO pc
FROM table1
WHERE id = '&ID';
DBMS_OUTPUT.ENABLE;
dynamic_sql :=
'SELECT ID from pp
WHERE ( TO_CHAR(cdate, ''yyyy/mm/dd'') =
TO_CHAR (:a, ''yyyy/mm/dd''))
AND aid IN (SELECT aid FROM ppd WHERE TO_CHAR(cdate, ''yyyy/mm/dd'') =
TO_CHAR (:b, ''yyyy/mm/dd'')
AND cid = :c )
AND cid <> :d';
OPEN cur FOR dynamic_sql USING pc.cdate, pc.cdate, pc.id, pc.id;
LOOP
FETCH cur INTO id;
EXIT WHEN cur%NOTFOUND;
v_count := v_count + 1;
DBMS_OUTPUT.PUT_LINE (' Id:' || id);
END LOOP;
CLOSE cur;
IF (v_count > 0)
THEN
DBMS_OUTPUT.PUT_LINE ( 'Count: ' || v_count || ' SQL: ' || dynamic_sql);
RAISE unmarked_ids;
END IF;
DBMS_OUTPUT.PUT_LINE('SQL ended successfully');
EXCEPTION
WHEN unmarked_ids
THEN
DBMS_OUTPUT.put_line (
'Found ID's that not marked with the current id.');
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (
'No data found in table1 with the current id ' || '&ID');
END;
There are bind variables in the query. One of them is date, there are three more.
The count and ID's are required to be shown which will later be reported.
You could store the rowid in a temporary table along with an index value (0...n) and then use a while loop to go through the index values and join to the real table using the rowid.