00933. 00000 - "SQL command not properly ended" DYNAMIC SQL - sql

DECLARE
CURSOR c_ddy (p_table_name VARCHAR2, p_table_name_2 VARCHAR2)
IS
(SELECT column_name
FROM ( SELECT column_name
FROM user_tab_columns
WHERE table_name = p_table_name
ORDER BY column_name));
TYPE t_content IS TABLE OF VARCHAR2 (9000)
INDEX BY BINARY_INTEGER;
a_content t_content;
l_sql VARCHAR2 (1000);
BEGIN
FOR r_ddy IN c_ddy ('TABLE_a', 'TABLE_B')
LOOP
l_sql :=
'SELECT '
|| r_ddy.column_name
|| ' FROM TABLE_A '
|| 'MINUS'
|| 'SELECT '
|| r_ddy.column_name
|| 'FROM TABLE_B';
EXECUTE IMMEDIATE l_sql BULK COLLECT INTO a_content;
DBMS_OUTPUT.put_line (l_sql);
END LOOP;
END;
Trying to output every column in TABLE_A minus every column in TABLE_B.

A space is missing in the SQL string.
Try this:
l_sql :=
'SELECT '
|| r_ddy.column_name
|| ' FROM TABLE_A '
|| ' MINUS '
|| ' SELECT '
|| r_ddy.column_name
|| ' FROM TABLE_B';
UPD: For some reason the spaces were gone before. Now I put them again.

Related

How to execute query in string mode in pl/sql?

I m trying to execute the procedure but it is showing the errror of missing expression while executing this line execute immediate sqlQuery into test;
My query returns 6 columns which i need to store into the variables , please help to execute this query.
procedure getAttributeOptions(subID number, compID number,docNumber varchar2,transType varchar2 ,rowNum varchar2 ,
Attribute1 out varchar2,Attribute2 out varchar2,Attribute3 out varchar2,Attribute4 out varchar2,
Attribute5 out varchar2, Attribute6 out varchar2) is
sqlQuery varchar2(4000);
storageColumns varchar2(4000);
colName varchar2(1000);
tableName varchar2(1000);
primaryKey varchar2(1000);
test varchar2(4000);
begin
colName:=' ATTRIBUTE_OPTION_1,ATTRIBUTE_OPTION_2,ATTRIBUTE_OPTION_3,ATTRIBUTE_OPTION_4,ATTRIBUTE_OPTION_5,ATTRIBUTE_OPTION_6 ';
storageColumns:=' Attribute1,Attribute2,Attribute3,Attribute4,Attribute5,Attribute6 ';
if transType = TY_ISSUE then
tableName:='preq_master_detail';
primaryKey:='req_number';
elsif transType=TY_TRANSFER then
tableName:='pinv_transfer_detail';
primaryKey:='transfer_id';
elsif transType=TY_RECEIVE then
tableName:='ppo_master_detail';
primaryKey:='po_number';
elsif transType=TY_MANUAL then
tableName:='part_manual_adjustment';
primaryKey:='adjustment_id';
end if;
dbms_output.put_line(tableName);
if tableName is not null then
begin
sqlQuery:='select ' || colName || 'into ' || storageColumns || 'from ' || tableName ;
sqlQuery:=sqlQuery || ' where subscriber_id=' || subID;
sqlQuery:=sqlQuery || ' and company_id=' || compID;
sqlQuery:=sqlQuery || ' and ' || primaryKey ||'='|| '''' || docNumber || '''' || ' and row_number ='||rowNum;
dbms_output.put_line(sqlQuery);
execute immediate sqlQuery into test;--issue in this line
dbms_output.put_line(Attribute1);
dbms_output.put_line(Attribute2);
dbms_output.put_line(Attribute3);
dbms_output.put_line(Attribute4);
dbms_output.put_line(Attribute5);
dbms_output.put_line(Attribute6);
exception when NO_DATA_FOUND then return ;
end;
end if;
end;
You are placing the list of variables for your INTO clause inside the SQL, rather than outside in PL/SQL. You need to use put the INTO clause outside. Hopefully you can hard-code that clause:
sqlQuery:='select ' || colName || 'from ' || tableName ;
. . .
execute immediate sqlQuery into Attribute1,Attribute2,Attribute3,Attribute4,Attribute5,Attribute6;
While you are at it, you should use bind variables for your WHERE clause:
. . .
sqlQuery:=sqlQuery || ' where subscriber_id=:subid';
sqlQuery:=sqlQuery || ' and company_id=:compID';
sqlQuery:=sqlQuery || ' and ' || primaryKey ||'= :docno'|| ' and row_number =:rowNum';
execute immediate sqlQuery
INTO Attribute1,Attribute2,Attribute3,Attribute4,Attribute5,Attribute6
USING subid,compid,docNumber,rowNum;
That will make your DBA happy.

PLSQL procedure for automatic column type changing

Let's assume following table:
drop table test1;
create table test1(
A number(10)
);
insert into test1 values (1);
insert into test1 values (10);
So as you can see table TEST1 is already populated. What i need to do is to change types of column A to varchar2. Since this column has values we can't just use following code:
alter table test1 modify A varchar2(10);
So i have wrote stored procedure which:
Renames column A to A1 ->
Then adds new column called A of type varchar2 ->
Then updates column A with values from column A1 ->
And ultimately drops old column A1.
Code which runs this process is following:
create or replace procedure change_col_type_to_varchar2(p_tab in varchar2, p_col in varchar2)
is
v_string clob;
cursor cur is
select column_name
from all_tab_columns
where table_name = upper(p_tab) and
column_name in (select regexp_substr(p_col,'[^,]+', 1, level) from dual
connect by regexp_substr(p_col, '[^,]+', 1, level) is not null);
begin
for i in cur loop
v_string := 'alter table ' || p_tab || ' rename column ' || i.column_name || ' to ' || i.column_name || '1' || ';';
dbms_lob.append(v_string,''||chr(10)||'');
dbms_lob.append(v_string, 'alter table ' || p_tab || ' add ' || i.column_name || ' varchar2(10);');
dbms_lob.append(v_string,''||chr(10)||'');
dbms_lob.append(v_string, 'update ' || p_tab || ' set ' || i.column_name || ' = ' || i.column_name || '1' || ';');
dbms_lob.append(v_string,''||chr(10)||'');
dbms_lob.append(v_string, 'alter table ' || p_tab || ' drop column ' || i.column_name || '1' || ';');
EXECUTE IMMEDIATE v_string;
DBMS_OUTPUT.PUT_LINE(v_string);
v_string := NULL;
end loop;
end;
I'am trying to apply this procedure to TEST1:
begin
change_col_type_to_varchar2('TEST1', 'A');
end;
And get error:
Error report -
ORA-23290: This operation may not be combined with any other operation
ORA-06512: at "YAVORSKYIY_DM.CHANGE_COL_TYPE_TO_VARCHAR2", line 19
ORA-06512: at "YAVORSKYIY_DM.CHANGE_COL_TYPE_TO_VARCHAR2", line 19
ORA-06512: at line 2
23290. 00000 - "This operation may not be combined with any other operation"
*Cause: ALTER TABLE RENAME COLUMN/CONSTRAINT operation was given in
conjunction with another ALTER TBALE Operation. This is not
allowed.
*Action: Ensure that RENAME COLUMN/CONSTRAINT is the only operation
specified in the ALTER TABLE.
But just typing :
alter table test1 rename column A to A1;
alter table test1 add A varchar2(100);
update test1 set A = A1;
alter table test1 drop column A1;
Works perfect.
Does anybody have any ideas about how to overcome this problem?
Appreciate your help.
the below will do what you asked for.
declare
procedure change_col_type_to_varchar2(p_tab in varchar2, p_col in varchar2)
is
v_string clob;
cursor cur is
select column_name
from all_tab_columns
where table_name = upper(p_tab) and
column_name in (select regexp_substr(p_col,'[^,]+', 1, level)
from dual
connect by regexp_substr(p_col, '[^,]+', 1, level) is not null);
begin
for i in cur loop
v_string := 'alter table ' || p_tab || ' rename column ' || i.column_name || ' to ' || i.column_name || '1';
execute immediate v_string;
v_string := 'alter table ' || p_tab || ' add ' || i.column_name || ' varchar2(10)';
execute immediate v_string;
v_string := 'update ' || p_tab || ' set ' || i.column_name || ' = ' || i.column_name || '1' ;
execute immediate v_string;
v_string := 'alter table ' || p_tab || ' drop column ' || i.column_name || '1' ;
execute immediate v_string;
v_string := NULL;
end loop;
end;
begin
DBMS_OUTPUT.PUT_LINE('Before calling');
change_col_type_to_varchar2('TEST1','A');
DBMS_OUTPUT.PUT_LINE('After calling');
end;
Well, execute each statement alone, instead of concatenating them. And you don't need LOBs, varchar2 for each one should be enough.
I propose other algorithm.
create new table 'table2' with varchar column;
select all values from table1.A and insert to table2 with to_char() conversion;
drop table1;
rename table2 to table1;
profit!

How to find all columns in a table which containing the chr(0) character in oracle [duplicate]

Is it possible to search every field of every table for a particular value in Oracle?
There are hundreds of tables with thousands of rows in some tables so I know this could take a very long time to query. But the only thing I know is that a value for the field I would like to query against is 1/22/2008P09RR8.
<
I've tried using this statement below to find an appropriate column based on what I think it should be named but it returned no results.
SELECT * from dba_objects
WHERE object_name like '%DTN%'
There is absolutely no documentation on this database and I have no idea where this field is being pulled from.
Any thoughts?
Quote:
I've tried using this statement below
to find an appropriate column based on
what I think it should be named but it
returned no results.*
SELECT * from dba_objects WHERE
object_name like '%DTN%'
A column isn't an object. If you mean that you expect the column name to be like '%DTN%', the query you want is:
SELECT owner, table_name, column_name FROM all_tab_columns WHERE column_name LIKE '%DTN%';
But if the 'DTN' string is just a guess on your part, that probably won't help.
By the way, how certain are you that '1/22/2008P09RR8' is a value selected directly from a single column? If you don't know at all where it is coming from, it could be a concatenation of several columns, or the result of some function, or a value sitting in a nested table object. So you might be on a wild goose chase trying to check every column for that value. Can you not start with whatever client application is displaying this value and try to figure out what query it is using to obtain it?
Anyway, diciu's answer gives one method of generating SQL queries to check every column of every table for the value. You can also do similar stuff entirely in one SQL session using a PL/SQL block and dynamic SQL. Here's some hastily-written code for that:
SET SERVEROUTPUT ON SIZE 100000
DECLARE
match_count INTEGER;
BEGIN
FOR t IN (SELECT owner, table_name, column_name
FROM all_tab_columns
WHERE owner <> 'SYS' and data_type LIKE '%CHAR%') LOOP
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM ' || t.owner || '.' || t.table_name ||
' WHERE '||t.column_name||' = :1'
INTO match_count
USING '1/22/2008P09RR8';
IF match_count > 0 THEN
dbms_output.put_line( t.table_name ||' '||t.column_name||' '||match_count );
END IF;
END LOOP;
END;
/
There are some ways you could make it more efficient too.
In this case, given the value you are looking for, you can clearly eliminate any column that is of NUMBER or DATE type, which would reduce the number of queries. Maybe even restrict it to columns where type is like '%CHAR%'.
Instead of one query per column, you could build one query per table like this:
SELECT * FROM table1
WHERE column1 = 'value'
OR column2 = 'value'
OR column3 = 'value'
...
;
I did some modification to the above code to make it work faster if you are searching in only one owner.
You just have to change the 3 variables v_owner, v_data_type and v_search_string to fit what you are searching for.
SET SERVEROUTPUT ON SIZE 100000
DECLARE
match_count INTEGER;
-- Type the owner of the tables you are looking at
v_owner VARCHAR2(255) :='ENTER_USERNAME_HERE';
-- Type the data type you are look at (in CAPITAL)
-- VARCHAR2, NUMBER, etc.
v_data_type VARCHAR2(255) :='VARCHAR2';
-- Type the string you are looking at
v_search_string VARCHAR2(4000) :='string to search here...';
BEGIN
FOR t IN (SELECT table_name, column_name FROM all_tab_cols where owner=v_owner and data_type = v_data_type) LOOP
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM '||t.table_name||' WHERE '||t.column_name||' = :1'
INTO match_count
USING v_search_string;
IF match_count > 0 THEN
dbms_output.put_line( t.table_name ||' '||t.column_name||' '||match_count );
END IF;
END LOOP;
END;
/
I know this is an old topic. But I see a comment to the question asking if it could be done in SQL rather than using PL/SQL. So thought to post a solution.
The below demonstration is to Search for a VALUE in all COLUMNS of all TABLES in an entire SCHEMA:
Search a CHARACTER type
Let's look for the value KING in SCOTT schema.
SQL> variable val varchar2(10)
SQL> exec :val := 'KING'
PL/SQL procedure successfully completed.
SQL> SELECT DISTINCT SUBSTR (:val, 1, 11) "Searchword",
2 SUBSTR (table_name, 1, 14) "Table",
3 SUBSTR (column_name, 1, 14) "Column"
4 FROM cols,
5 TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select '
6 || column_name
7 || ' from '
8 || table_name
9 || ' where upper('
10 || column_name
11 || ') like upper(''%'
12 || :val
13 || '%'')' ).extract ('ROWSET/ROW/*') ) ) t
14 ORDER BY "Table"
15 /
Searchword Table Column
----------- -------------- --------------
KING EMP ENAME
SQL>
Search a NUMERIC type
Let's look for the value 20 in SCOTT schema.
SQL> variable val NUMBER
SQL> exec :val := 20
PL/SQL procedure successfully completed.
SQL> SELECT DISTINCT SUBSTR (:val, 1, 11) "Searchword",
2 SUBSTR (table_name, 1, 14) "Table",
3 SUBSTR (column_name, 1, 14) "Column"
4 FROM cols,
5 TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select '
6 || column_name
7 || ' from '
8 || table_name
9 || ' where upper('
10 || column_name
11 || ') like upper(''%'
12 || :val
13 || '%'')' ).extract ('ROWSET/ROW/*') ) ) t
14 ORDER BY "Table"
15 /
Searchword Table Column
----------- -------------- --------------
20 DEPT DEPTNO
20 EMP DEPTNO
20 EMP HIREDATE
20 SALGRADE HISAL
20 SALGRADE LOSAL
SQL>
Yes you can and your DBA will hate you and will find you to nail your shoes to the floor because that will cause lots of I/O and bring the database performance really down as the cache purges.
select column_name from all_tab_columns c, user_all_tables u where c.table_name = u.table_name;
for a start.
I would start with the running queries, using the v$session and the v$sqlarea. This changes based on oracle version. This will narrow down the space and not hit everything.
Here is another modified version that will compare a lower substring match. This works in Oracle 11g.
DECLARE
match_count INTEGER;
-- Type the owner of the tables you are looking at
v_owner VARCHAR2(255) :='OWNER_NAME';
-- Type the data type you are look at (in CAPITAL)
-- VARCHAR2, NUMBER, etc.
v_data_type VARCHAR2(255) :='VARCHAR2';
-- Type the string you are looking at
v_search_string VARCHAR2(4000) :='%lower-search-sub-string%';
BEGIN
FOR t IN (SELECT table_name, column_name FROM all_tab_cols where owner=v_owner and data_type = v_data_type) LOOP
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM '||t.table_name||' WHERE lower('||t.column_name||') like :1'
INTO match_count
USING v_search_string;
IF match_count > 0 THEN
dbms_output.put_line( t.table_name ||' '||t.column_name||' '||match_count );
END IF;
END LOOP;
END;
/
I modified Flood's script to execute once for each table rather than for every column of each table for faster execution. It requires Oracle 11g or greater.
set serveroutput on size 100000
declare
v_match_count integer;
v_counter integer;
-- The owner of the tables to search through (case-sensitive)
v_owner varchar2(255) := 'OWNER_NAME';
-- A string that is part of the data type(s) of the columns to search through (case-insensitive)
v_data_type varchar2(255) := 'CHAR';
-- The string to be searched for (case-insensitive)
v_search_string varchar2(4000) := 'FIND_ME';
-- Store the SQL to execute for each table in a CLOB to get around the 32767 byte max size for a VARCHAR2 in PL/SQL
v_sql clob := '';
begin
for cur_tables in (select owner, table_name from all_tables where owner = v_owner and table_name in
(select table_name from all_tab_columns where owner = all_tables.owner and data_type like '%' || upper(v_data_type) || '%')
order by table_name) loop
v_counter := 0;
v_sql := '';
for cur_columns in (select column_name from all_tab_columns where
owner = v_owner and table_name = cur_tables.table_name and data_type like '%' || upper(v_data_type) || '%') loop
if v_counter > 0 then
v_sql := v_sql || ' or ';
end if;
v_sql := v_sql || 'upper(' || cur_columns.column_name || ') like ''%' || upper(v_search_string) || '%''';
v_counter := v_counter + 1;
end loop;
v_sql := 'select count(*) from ' || cur_tables.table_name || ' where ' || v_sql;
execute immediate v_sql
into v_match_count;
if v_match_count > 0 then
dbms_output.put_line('Match in ' || cur_tables.owner || ': ' || cur_tables.table_name || ' - ' || v_match_count || ' records');
end if;
end loop;
exception
when others then
dbms_output.put_line('Error when executing the following: ' || dbms_lob.substr(v_sql, 32600));
end;
/
I was having following issues for #Lalit Kumars answer,
ORA-19202: Error occurred in XML processing
ORA-00904: "SUCCESS": invalid identifier
ORA-06512: at "SYS.DBMS_XMLGEN", line 288
ORA-06512: at line 1
19202. 00000 - "Error occurred in XML processing%s"
*Cause: An error occurred when processing the XML function
*Action: Check the given error message and fix the appropriate problem
Solution is:
WITH char_cols AS
(SELECT /*+materialize */ table_name, column_name
FROM cols
WHERE data_type IN ('CHAR', 'VARCHAR2'))
SELECT DISTINCT SUBSTR (:val, 1, 11) "Searchword",
SUBSTR (table_name, 1, 14) "Table",
SUBSTR (column_name, 1, 14) "Column"
FROM char_cols,
TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select "'
|| column_name
|| '" from "'
|| table_name
|| '" where upper("'
|| column_name
|| '") like upper(''%'
|| :val
|| '%'')' ).extract ('ROWSET/ROW/*') ) ) t
ORDER BY "Table"
/
I would do something like this (generates all the selects you need).
You can later on feed them to sqlplus:
echo "select table_name from user_tables;" | sqlplus -S user/pwd | grep -v "^--" | grep -v "TABLE_NAME" | grep "^[A-Z]" | while read sw;
do echo "desc $sw" | sqlplus -S user/pwd | grep -v "\-\-\-\-\-\-" | awk -F' ' '{print $1}' | while read nw;
do echo "select * from $sw where $nw='val'";
done;
done;
It yields:
select * from TBL1 where DESCRIPTION='val'
select * from TBL1 where ='val'
select * from TBL2 where Name='val'
select * from TBL2 where LNG_ID='val'
And what it does is - for each table_name from user_tables get each field (from desc) and create a select * from table where field equals 'val'.
if we know the table and colum names but want to find out the number of times string is appearing for each schema:
Declare
owner VARCHAR2(1000);
tbl VARCHAR2(1000);
cnt number;
ct number;
str_sql varchar2(1000);
reason varchar2(1000);
x varchar2(1000):='%string_to_be_searched%';
cursor csr is select owner,table_name
from all_tables where table_name ='table_name';
type rec1 is record (
ct VARCHAR2(1000));
type rec is record (
owner VARCHAR2(1000):='',
table_name VARCHAR2(1000):='');
rec2 rec;
rec3 rec1;
begin
for rec2 in csr loop
--str_sql:= 'select count(*) from '||rec.owner||'.'||rec.table_name||' where CTV_REMARKS like '||chr(39)||x||chr(39);
--dbms_output.put_line(str_sql);
--execute immediate str_sql
execute immediate 'select count(*) from '||rec2.owner||'.'||rec2.table_name||' where column_name like '||chr(39)||x||chr(39)
into rec3;
if rec3.ct <> 0 then
dbms_output.put_line(rec2.owner||','||rec3.ct);
else null;
end if;
end loop;
end;
Procedure to Search Entire Database:
CREATE or REPLACE PROCEDURE SEARCH_DB(SEARCH_STR IN VARCHAR2, TAB_COL_RECS OUT VARCHAR2) IS
match_count integer;
qry_str varchar2(1000);
CURSOR TAB_COL_CURSOR IS
SELECT TABLE_NAME,COLUMN_NAME,OWNER,DATA_TYPE FROM ALL_TAB_COLUMNS WHERE DATA_TYPE in ('NUMBER','VARCHAR2') AND OWNER='SCOTT';
BEGIN
FOR TAB_COL_REC IN TAB_COL_CURSOR
LOOP
qry_str := 'SELECT COUNT(*) FROM '||TAB_COL_REC.OWNER||'.'||TAB_COL_REC.TABLE_NAME||
' WHERE '||TAB_COL_REC.COLUMN_NAME;
IF TAB_COL_REC.DATA_TYPE = 'NUMBER' THEN
qry_str := qry_str||'='||SEARCH_STR;
ELSE
qry_str := qry_str||' like '||SEARCH_STR;
END IF;
--dbms_output.put_line( qry_str );
EXECUTE IMMEDIATE qry_str INTO match_count;
IF match_count > 0 THEN
dbms_output.put_line( qry_str );
--dbms_output.put_line( TAB_COL_REC.TABLE_NAME ||' '||TAB_COL_REC.COLUMN_NAME ||' '||match_count);
TAB_COL_RECS := TAB_COL_RECS||'##'||TAB_COL_REC.TABLE_NAME||'##'||TAB_COL_REC.COLUMN_NAME;
END IF;
END LOOP;
END SEARCH_DB;
Execute Statement
DECLARE
SEARCH_STR VARCHAR2(200);
TAB_COL_RECS VARCHAR2(200);
BEGIN
SEARCH_STR := 10;
SEARCH_DB(
SEARCH_STR => SEARCH_STR,
TAB_COL_RECS => TAB_COL_RECS
);
DBMS_OUTPUT.PUT_LINE('TAB_COL_RECS = ' || TAB_COL_RECS);
END;
Sample Results
Connecting to the database test.
SELECT COUNT(*) FROM SCOTT.EMP WHERE DEPTNO=10
SELECT COUNT(*) FROM SCOTT.DEPT WHERE DEPTNO=10
TAB_COL_RECS = ##EMP##DEPTNO##DEPT##DEPTNO
Process exited.
Disconnecting from the database test.
I don't of a simple solution on the SQL promprt. Howeve there are quite a few tools like toad and PL/SQL Developer that have a GUI where a user can input the string to be searched and it will return the table/procedure/object where this is found.
There are some free tools that make these kind of search, for example, this one works fine and source code is available:
https://sites.google.com/site/freejansoft/dbsearch
You'll need the Oracle ODBC driver and a DSN to use this tool.
Modifying the code to search case-insensitively using a LIKE query instead of finding exact matches...
DECLARE
match_count INTEGER;
-- Type the owner of the tables you want to search.
v_owner VARCHAR2(255) :='USER';
-- Type the data type you're looking for (in CAPS). Examples include: VARCHAR2, NUMBER, etc.
v_data_type VARCHAR2(255) :='VARCHAR2';
-- Type the string you are looking for.
v_search_string VARCHAR2(4000) :='Test';
BEGIN
dbms_output.put_line( 'Starting the search...' );
FOR t IN (SELECT table_name, column_name FROM all_tab_cols where owner=v_owner and data_type = v_data_type) LOOP
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM '||t.table_name||' WHERE LOWER('||t.column_name||') LIKE :1'
INTO match_count
USING LOWER('%'||v_search_string||'%');
IF match_count > 0 THEN
dbms_output.put_line( t.table_name ||' '||t.column_name||' '||match_count );
END IF;
END LOOP;
END;
I found the best solution but it's a little slow. (It will work perfectly with all SQL IDE's.)
SELECT DISTINCT table_name, column_name, data_type
FROM user_tab_cols,
TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select '
|| column_name
|| ' from '
|| table_name
|| ' where lower('
|| column_name
|| ') like lower(''%'
|| 'your_text_here'
|| '%'')' ).extract ('ROWSET/ROW/*') ) ) a
where table_name not in (
select distinct table_name
from user_tab_cols where data_type like 'SDO%'
or data_type like '%LOB') AND DATA_TYPE = 'VARCHAR2'
order by table_name, column_name;
--it run completed -- no error
SET SERVEROUTPUT ON SIZE 100000
DECLARE
v_match_count INTEGER;
v_counter INTEGER;
v_owner VARCHAR2 (255) := 'VASOA';
v_search_string VARCHAR2 (4000) := '99999';
v_data_type VARCHAR2 (255) := 'CHAR';
v_sql CLOB := '';
BEGIN
FOR cur_tables
IN ( SELECT owner, table_name
FROM all_tables
WHERE owner = v_owner
AND table_name IN (SELECT table_name
FROM all_tab_columns
WHERE owner = all_tables.owner
AND data_type LIKE
'%'
|| UPPER (v_data_type)
|| '%')
ORDER BY table_name)
LOOP
v_counter := 0;
v_sql := '';
FOR cur_columns
IN (SELECT column_name, table_name
FROM all_tab_columns
WHERE owner = v_owner
AND table_name = cur_tables.table_name
AND data_type LIKE '%' || UPPER (v_data_type) || '%')
LOOP
IF v_counter > 0
THEN
v_sql := v_sql || ' or ';
END IF;
IF cur_columns.column_name is not null
THEN
v_sql :=
v_sql
|| 'upper('
|| cur_columns.column_name
|| ') ='''
|| UPPER (v_search_string)||'''';
v_counter := v_counter + 1;
END IF;
END LOOP;
IF v_sql is null
THEN
v_sql :=
'select count(*) from '
|| v_owner
|| '.'
|| cur_tables.table_name;
END IF;
IF v_sql is not null
THEN
v_sql :=
'select count(*) from '
|| v_owner
|| '.'
|| cur_tables.table_name
|| ' where '
|| v_sql;
END IF;
--v_sql := 'select count(*) from ' ||v_owner||'.'|| cur_tables.table_name ||' where '|| v_sql;
--dbms_output.put_line(v_sql);
--DBMS_OUTPUT.put_line (v_sql);
EXECUTE IMMEDIATE v_sql INTO v_match_count;
IF v_match_count > 0
THEN
DBMS_OUTPUT.put_line (v_sql);
dbms_output.put_line('Match in ' || cur_tables.owner || ': ' || cur_tables.table_name || ' - ' || v_match_count || ' records');
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
'Error when executing the following: '
|| DBMS_LOB.SUBSTR (v_sql, 32600));
END;
/
Borrowing, slightly enhancing and simplifying from this Blog post the following simple SQL statement seems to do the job quite well:
SELECT DISTINCT (:val) "Search Value", TABLE_NAME "Table", COLUMN_NAME "Column"
FROM cols,
TABLE (XMLSEQUENCE (DBMS_XMLGEN.GETXMLTYPE(
'SELECT "' || COLUMN_NAME || '" FROM "' || TABLE_NAME || '" WHERE UPPER("'
|| COLUMN_NAME || '") LIKE UPPER(''%' || :val || '%'')' ).EXTRACT ('ROWSET/ROW/*')))
ORDER BY "Table";
The Oracle LIKE condition allows wildcards to be used in the WHERE clause of a SELECT, INSERT, UPDATE, or DELETE statement.
%: to match any string of any length
Eg-
SELECT last_name
FROM customer_tab
WHERE last_name LIKE '%A%';
-: to match on a single character
Eg-
SELECT last_name
FROM customer_tab
WHERE last_name LIKE 'A_t';

How do i copy old columns to my new existing table?

I have an existing new table that has no columns yet. I want to copy all 10 columns in my old table. How do i do that? I don't want to drop the table so I could perform: create table newTable as select * from oldTable.
I don't want to drop the table so I could perform:
create table newTable as select * from oldTable.
Assuming your new table has at least 1 column BobC told you cannot have a table without any column, you can alter your table.
Alter new_table add (col1 varchar2(10)) , col2 ...);
Note that you need to mention all the column same as old table manually here.
If you don't want to do this manually then probably you would need a PLSQL block to do this.
CREATE OR REPLACE PROCEDURE creat_tbl_frm_tbl (tablname VARCHAR2)
AS
db_user VARCHAR2 (100) := USER;
TYPE t_rec IS RECORD
(
COLUMN_NAME VARCHAR2 (30 BYTE),
DATA_TYPE VARCHAR2 (106 BYTE),
DATA_LENGTH NUMBER
);
TYPE t_record IS TABLE OF t_rec;
-- initialization of record
v_record t_record := t_record ();
v_cntr NUMBER := 0;
v_status NUMBER;
sql_stmt VARCHAR2 (2000);
BEGIN
---dropping Already Existing temporary table
BEGIN
SELECT 1
INTO v_status
FROM all_objects
WHERE UPPER (object_name) = UPPER (tablname) AND owner = db_user;
--dbms_output.put_line( v_status );
IF v_status = 1
THEN
sql_stmt := 'drop table ' || tablname || '_new';
EXECUTE IMMEDIATE sql_stmt;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line ('Table not found--' || tablname);
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
'Error while dropping table-' || SQLCODE || SQLERRM);
END;
---------------------------------------------------------------------------
---- retrieving the columns of the table
BEGIN
SELECT column_name, data_type, data_length
BULK COLLECT INTO v_record
FROM all_tab_columns
WHERE table_name = UPPER (tablname)
ORDER BY column_id;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
'Error while retrieving the column details-' || SQLCODE || SQLERRM);
END;
FOR i IN 1 .. v_record.COUNT
LOOP
v_cntr := v_cntr + 1;
IF v_cntr = 1
THEN
IF v_record (i).data_type = 'DATE'
OR UPPER (v_record (i).data_type) = 'TIMESTAMP(6)'
THEN
sql_stmt :=
'create table '
|| ' '
|| tablname
|| '_new'
|| '('
|| v_record (i).column_name
|| ' '
|| v_record (i).data_type
|| ')';
ELSE
sql_stmt :=
'create table '
|| ' '
|| tablname
|| '_new'
|| '('
|| v_record (i).column_name
|| ' '
|| v_record (i).data_type
|| '('
|| v_record (i).data_length
|| '))';
END IF;
--dbms_output.put_line(sql_stmt);
EXECUTE IMMEDIATE sql_stmt;
ELSE
IF v_record (i).data_type = 'DATE'
OR UPPER (v_record (i).data_type) = 'TIMESTAMP(6)'
THEN
sql_stmt :=
'alter table'
|| ' '
|| tablname
|| '_new'
|| ' '
|| 'add ('
|| v_record (i).column_name
|| ' '
|| v_record (i).data_type
|| ')';
ELSE
sql_stmt :=
'alter table'
|| ' '
|| tablname
|| '_new'
|| ' '
|| 'add ('
|| v_record (i).column_name
|| ' '
|| v_record (i).data_type
|| '('
|| v_record (i).data_length
|| '))';
END IF;
--dbms_output.put_line(sql_stmt);
EXECUTE IMMEDIATE sql_stmt;
END IF;
END LOOP;
DBMS_OUTPUT.put_line ('Process Completed Successfully..!!');
END;
Output:
SQL> exec creat_tbl_frm_tbl('table2')
Process Completed Successfully..!!
PL/SQL procedure successfully completed.
SQL> select * from table2;
no rows selected
-- This is created with same columns as of passed table table2
SQL> select * from table2_new;
no rows selected
SELECT col1,col2,col3 --...
INTO newTable
FROM oldTable

Runtime Query in Oracle store procedures not returning proper result

This is first my stint with procedure and I am trying to execute below oracle procedure but facing some issue. Any inputs on this would be really helpful:
Issue:-----
I have a select query that returns two values:
src_Columns contains:
ID_ELEMENT
ID_ELEMENT_SA
Now, When I am trying to travesre a select-query(single column) result using "For Loop", I am not getting the values of the column rather I am getting its name only.
FOR columnItem IN (SELECT src_Columns FROM ELEM90_LNK_ELEM_BOSE)
LOOP
dbms_output.put_line('src_Columns 3: ' || columnItem.src_Columns);
query_test:= 'insert into ' || destination_Table || '(NAME,' || dest_Columns_Value || ') VALUES( ''' || src_name_Value || ''',''' || columnItem.dummyValue || ''')';
dbms_output.put_line('query_test:' || query_test);
execute immediate query_test;
END LOOP;
I mean the test query generated is following when i use variable name(src_columns):
insert into ATT_WTPART(NAME,STRINGVALUE) VALUES( 'ID_ELEMENT_SA','ID_ELEMENT_SA')
whereas if I use ID_ELEMENT_SA instead of src_Columns in FOR LOOP
FOR columnItem IN (SELECT ID_ELEMENT FROM ELEM90_LNK_ELEM_BOSE)
then I get proper values that are desired like
insert into ATT_WTPART(NAME,STRINGVALUE) VALUES( 'ID_ELEMENT_SA','ID05')
How can I make sure that I get the values even when I am using the variable name instead of any hard-coding
Below is the Complete Procedure:-------------
create or replace
PROCEDURE ELEM90_Lnk_Elem_ATT_WTPART_MK
AS
CURSOR targ_dest_relation IS
SELECT sourcecolumn FROM mapping where destinationtable='ATT_WTPART';
BEGIN
DECLARE
dest_Columns varchar2(1000);
src_Columns varchar2(1000);
src_Type varchar2(1000);
destination_Table varchar2(1000) := 'ATT_WTPART';
source_Table varchar2(1000) := 'ELEM90_LNK_ELEM_BOSE';
query_test varchar2(1000);
query_test2 varchar2(1000);
src_name varchar2(255);
src_Type_Value varchar2(255);
dest_Columns_Value varchar2(255);
src_name_Value varchar2(255);
for_query varchar2(1000);
for_query_data varchar2(1000);
dummyValue varchar2(1000);
BEGIN
FOR rec IN targ_dest_relation loop
dbms_output.put_line('destination_Table: ' || destination_Table);
dbms_output.put_line('source_Table: ' || source_Table);
src_Columns := rec.sourcecolumn;
dbms_output.put_line('src_Columns: ' || src_Columns);
src_Type := 'select data_type from user_tab_columns where table_name ='''||source_Table||'''and column_name='''|| src_Columns ||'''';
dbms_output.put_line('src_Type: ' || src_Type);
execute immediate src_Type INTO src_Type_Value;
dbms_output.put_line('src_Type_Value: ' || src_Type_Value);
dest_Columns := 'select DEST_COLUMN from ATT_PART_MAPPING where SOURCETYPE='''|| src_Type_Value || '''';
dbms_output.put_line('dest_Columns: ' || dest_Columns);
execute immediate dest_Columns INTO dest_Columns_Value;
dbms_output.put_line('dest_Columns_Value: ' || dest_Columns_Value);
src_name := 'select column_name from user_tab_columns where table_name ='''|| source_Table ||''' and column_name= ''' || src_Columns || '''';
dbms_output.put_line('src_name: ' || src_name);
execute immediate src_name INTO src_name_Value;
dbms_output.put_line('src_name_Value: ' || src_name_Value);
FOR columnItem IN (SELECT src_Columns FROM ELEM90_LNK_ELEM_BOSE)
LOOP
dbms_output.put_line('src_Columns 3: ' || columnItem.src_Columns);
query_test:= 'insert into ' || destination_Table || '(NAME,' || dest_Columns_Value || ') VALUES( ''' || src_name_Value || ''',''' || columnItem.dummyValue || ''')';
dbms_output.put_line('query_test:' || query_test);
execute immediate query_test;
END LOOP;
END loop;
END;
END;
The problem with the line
FOR columnItem IN (SELECT src_Columns FROM ELEM90_LNK_ELEM_BOSE)
is that src_Columns is a local variable. As a result, you end up selecting the same value for each row in ELEM90_LNK_ELEM_BOSE.
If you want the value of the local variable to be used as a column name in the query, you must use dynamic SQL instead. Try replacing FOR columnItem ... LOOP ... END LOOP with the following:
OPEN curs FOR 'SELECT ' || src_Columns || ' FROM ELEM90_LNK_ELEM_BOSE';
LOOP
FETCH curs INTO column_value;
EXIT WHEN curs%NOTFOUND;
dbms_output.put_line('src_Columns 3: ' || column_value);
query_test:= 'insert into ' || destination_Table || '(NAME,' || dest_Columns_Value || ') VALUES( ''' || src_name_Value || ''',''' || column_value || ''')';
dbms_output.put_line('query_test:' || query_test);
execute immediate query_test;
END LOOP;
CLOSE curs;
You will need to declare the following extra variables:
curs SYS_REFCURSOR;
column_value VARCHAR2(4000);
However, in truth it would probably be better to remove the loop entirely. You can replace it with an INSERT INTO ... SELECT ... FROM ... statement instead, such as the following:
EXECUTE IMMEDIATE 'INSERT INTO ' || destination_Table || ' (NAME,' ||
dest_Columns_Value || ') SELECT :name,' || src_Columns ||
' FROM ELEM90_LNK_ELEM_BOSE' USING src_name_Value;
This also gets rid of the need for the two local variables curs and column_value, and is also likely to be considerably faster, as there's no need to parse dynamic SQL once for each row in the destination table.
Is it working better if you try this one:
query_test:= 'insert into ' || destination_Table ||
'(NAME,'||dest_Columns_Value||') VALUES (:p1, :p2)';
execute immediate query_test USING src_name_Value, columnItem.dummyValue;
At least it should have a positive impact on performance.