Oracle SQL: Update with variable table name and fixed column name - sql

I am a beginner with SQL and have a problem:
I have a DB with a big number of tables. Some of the tables have a column with the name "lab".
In this colums are values I need to be changed.
So I managed to get the names of the tables via
SELECT CNAME,TNAME FROM SYSTEM.COL WHERE CNAME = 'LAB';
And I know my update command
update TNAME set LAB='VALUE' WHERE LAB='OLDVALUE'
But I can not manage to connect both statements via a variable TNAME or something. I tried to use execute immediate, but that did me no good.

If its Oracle, something like this should do it:
BEGIN
FOR cur_tabs_cols IN ( SELECT CNAME,TNAME FROM SYSTEM.COL WHERE CNAME = 'LAB'; )
LOOP
EXECUTE IMMEDIATE 'UPDATE ' || cur_tabs_cols.TNAME || ' SET LAB = ''VALUE'' WHERE LAB = ''OLDVALUE''';
END LOOP;
COMMIT;
END;

You would need to write pl/sql for this.
The first thing is, please don't use SYSTEM.COL. Instead use the data dictionary view USER_TAB_COLS or USER_TAB_COLUMNS. (or ALL_TAB_COLS if in other schema)
EXECUTE IMMEDIATE would be what you want here.
BEGIN
FOR i IN (SELECT table_name
FROM user_tab_cols
WHERE column_name = 'LAB')
LOOP
EXECUTE IMMEDIATE
'UPDATE ' || i.table_name || ' set LAB = :value where LAB = :oldvalue'
USING 'value', 'oldvalue';
END LOOP;
END;
You can (and should) use a bind variable for value and oldvalue, just not for the table name.

Related

Creating a table if it doesn't exist already

I'm trying to create a table if it doesn't exist already. I'm currently checking to see if it exists in DBA_TABLES first and if that query returns nothing then insert. Is there a way to just check in the same statement so I don't have to break it up into separate queries?
This is what I have currently.
BEGIN
SELECT COUNT(*)
INTO lvnTableExists
FROM DBA_TABLES
WHERE Table_Name = 'SOME_TABLE';
IF lvnTableExists = 0 THEN
EXECUTE IMMEDIATE 'CREATE TABLE SOME_TABLE AS (SELECT * FR0M OTHER_TABLE)';
END IF;
END;
This is something that I'm going for.
DECLARE
sql VARCHAR2(100000);
BEGIN
sql := 'CREATE TABLE SOME_TABLE ' ||
'AS (SELECT * FROM OTHER_TABLE) ' ||
'WHERE NOT EXISTS (SELECT NULL ' ||
'FROM DBA_OBJECTS d WHERE d.Object_Name = 'SOME_TABLE' AND ' ||
'd.Owner = 'SOME_TABLE')';
EXECUTE IMMEDIATE sql;
END;
The problem is that, you can't put a WHERE NOT EXISTS in a CREATE TABLE AS statement.
Yes, that's really a shame that Oracle doesn't have that functionality. I'm sure it will come some day. Until then, if you want to write a PL/SQL wrapper, why not do it like that:
DEClARE
table_exists_already exception;
pragma exception_init(table_exists_already, -955 );
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE SOMETABLE...';
EXCEPTION WHEN table_exists_already THEN
DBMS_OUTPUT.PUT_LINE('Table sometable already exists');
END;
/

Get all ids in a database

I want to get all the ids in a database from all columns that have an ID field.
My script so far is:
BEGIN
FOR tname IN (select table_name from all_tab_columns where column_name = 'ID' and owner='PACC_USER') LOOP
EXECUTE IMMEDIATE
'select unique id from ' || tname;
END LOOP;
End;
I get the error PLS-00306: wrong number or types of arguments in call to '||'. What is the problem exactly? Any help is welcomed :)
In your code tname is a record for referencing the cursor result set i.e. a namespace not an attribute. Fix it like this:
BEGIN
FOR tname IN (select table_name
from all_tab_columns
where column_name = 'ID' and owner='PACC_USER')
LOOP
EXECUTE IMMEDIATE
'select unique id from ' || tname.table_name ;
END LOOP;
End;
One would hope that a column called ID would return unique rows without needing the unique keyword but we live in troubled times.
Your code needs to select results into something: PL/SQL is not T-SQL, it requires target variables. So let's improve your code a bit more.
declare
ids_nt sys.dbms-debug_vc2coll;
BEGIN
FOR tname IN (select table_name
from all_tab_columns
where column_name = 'ID' and owner='PACC_USER')
LOOP
EXECUTE IMMEDIATE
'select unique id from ' || tname.table_name
bulk collect into ids_nt;
dbms_output.put_line('IDS for table '|| tname.table_name);
for idx in ids_nt.first() .. ids_nt.last loop
dbms_output.put_line(ids_nt(idx));
end loop;
END LOOP;
End;
Maybe this isn't the kind of thing you want to do with the IDs. If so please edit your question to clarify your intent.
Select column_name,table name from all_tab_column where upper(column_name)=upper('Id') ;

SAP HANA execute query generated within a procedure

I am new with SAP HANA, I am trying to generate a query and execute it within a stored procedure.
I got an error and I am not sure that HANA can do something like that.
Here my code
CREATE PROCEDURE "PROCEDURE_IBA_TESTCSV"(
IN SCHEMA_NAME VARCHAR(100))
LANGUAGE SQLSCRIPT SQL SECURITY INVOKER AS
BEGIN
DECLARE T VARCHAR(1000);
DECLARE TA VARCHAR(1000);
SELECT
' SELECT ' || MAX(C_1) || IFNULL(MAX(C_2),'')|| IFNULL(MAX(C_3),'') ||' AS STATEMENT FROM ' || SCHEMA_NAME || '.' || TABLE_NAME || ' ' INTO T
FROM (
SELECT POSITION, DATA_TYPE_ID, COLUMN_NAME ,SCHEMA_NAME, TABLE_NAME ,
CASE WHEN POSITION = 1 THEN
' CASE WHEN ( '|| COLUMN_NAME ||' IS NULL ) THEN '''' ELSE REPLACE(TO_CHAR(' || COLUMN_NAME || '),''.'','','') END' END AS C_1,
CASE WHEN POSITION = 2 THEN '||''#''|| CASE WHEN ( '|| COLUMN_NAME ||' IS NULL ) THEN '''' ELSE TO_NVARCHAR('||COLUMN_NAME||') END' END AS C_2,
CASE WHEN POSITION = 3 THEN '||''#''|| CASE WHEN ( '|| COLUMN_NAME ||' IS NULL ) THEN '''' ELSE TO_NVARCHAR('||COLUMN_NAME||') END' END AS C_3
FROM (
select SCALE,SCHEMA_NAME,position,TABLE_NAME,column_name, data_type_id from TABLE_COLUMNS where
schema_name ='IMPORT_KT_STAMM_IK_348BA_20160706' AND TABLE_NAME='CLS_220_KTHISTORIE')) group by SCHEMA_NAME,TABLE_NAME;
execute immediate :T ;
INSERT INTO Test SELECT :T from DUMMY;
END;
With execute :T I get this output
I would like to store SUM(length) of this output into a variable within the same procedure.
Is that possible ? Any help ?
thanks in advance
Ok, now I understand, where this is going.
As you want to work with tables of different shape, you won't be able to avoid dynamic SQL altogether.
But since you always melt it into a single column, you could simply store that transformed data into, say a temporary table, and run the SUM(LENGTH(()) on that.
Not sure though why you want to go through this rather painful exercise, instead of simply exporting the data into some folder and checking the resulting size there.
I don't quite get why you use dynamic SQL here. With dynamic SQL (exec/execute immediate) you don't get access to the result set.
Alternatively you can use cursors.
You can provide parameters for SCHEMA_NAME and TABLE_NAME and be 'dynamic' that way.
I guess this question is related to SAP HANA getting csv data size right?
I modified my code:
I write "insert into Table SELECT " instead "SELECT" in line 8
and now I get data in table

Dynamic statement in a trigger

I want to run a trigger on Oracle to update several fields of a table with data coming from another table, after an update event. I want to use dynamic SQL statements. Both tables have a lot of fields in common, different by a prefix. The use of "execute immediate" works only if the field I'm updating is explicit. As soon as I use a variable for the field name, it doesn't work. Any idea?
Here is the code :
create or replace TRIGGER AF_UPDATE_PRODUCT_REQUEST
AFTER UPDATE ON PRODUCT_REQUEST
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
WHEN (old.PREQCOMPLETE=1)
DECLARE
product_fieldname varchar2(100);
counter number(1);
tata number(3);
old_value VARCHAR2(500);
new_value VARCHAR2(500);
BEGIN
tata:=0;
FOR c1 in (SELECT column_name from user_tab_columns WHERE table_name='PRODUCT_REQUEST')
LOOP
old_value:=to_char(:old.PREQDESC2);
new_value:=to_char(:new.PREQDESC2);
IF old_value<>new_value THEN
product_fieldname:=replace(c1.column_name,'PREQ','PU');
select count(*) into counter from user_tab_columns WHERE table_name='PRODUCT' and column_name=product_fieldname;
IF counter=1 THEN
tata:=tata+1;
/*execute immediate 'update product set '|| product_fieldname ||'=:new.'|| c1.column_name ||' where pupname=:old.preqpname';*/
/*execute immediate 'update product set pushelflife=16 where pupname=:d3' using :old.preqpname;*/
IF product_fieldname='PUSHELFLIFE' THEN
/*execute immediate 'update product set pushelflife=:d2 where pupname=:d3' using 15,:old.preqpname;*/
execute immediate 'update product set :d1=:d2 where pupname=:d3' using product_fieldname,15,:old.preqpname;
END IF;
END IF;
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
You cannot pass in object or column names as bind variables to a dynamic SQL statement. You would have to construct the dynamic SQL statement using those column names. Something like
execute immediate 'update product ' ||
' set ' || product_fieldname || ' = :val '
' where pupname = :key'
using 15, :old.preqpname

how to use a procedure parameter in a query

how do i access the procedure parameters inside the same procedure using a query
for example: see this procedure
procedure game(left in tab.left%type,right in tab.right%type,...)
is
--some local variables
begin
merge into tgt_table
using subquery --(here is what i need to use the parameters)
on some condition
when matched then
update the tgt table
when not matched then
insert the table;
end game;
In above procedure and in merge statement, i need a query such that it uses the parameters value as a table reference and using those values it either updates or inserts into the table based on the condition given.
Help me please. Thanks in advance
You would need to use dynamic SQL if your parameters define the table to use - something like:
procedure game(left in tab.left%type,right in tab.right%type,...)
is
--some local variables
l_sql long;
begin
l_sql := 'merge into tgt_table'
|| ' using ' || left
|| ' on some condition'
|| ' when matched then'
|| ' update ' || right
|| ' when not matched then'
|| ' insert the table';
execute immediate l_sql;
end game;
However, you have a lot more work left to do, since the condition, update and insert clauses all need to change according to the tables being used. I'm not convinced this procure will be particularly useful in fact.
Please read http://download.oracle.com/docs/cd/B14117_01/appdev.101/b10807/06_ora.htm#sthref777