Error while trying to update values (cursor) - sql

I'm trying to write a code which update my table base on table2.
Table1 contain column like: COLUMN1,COLUMN2,COLUMN3...
Table2 contain column 2 column:
-First column contain name of the column from the table1 which should be update
-Second contain VALUE which should be set
So Table2 output:
columnname,value
----------------
COLUMN1 , 'sometext'
COLUMN2 , 'somethingelse'
set serveroutput on;
declare cursor doupdate
is
select columnname,value from TABLE2;
nazwa TABLE2.columnname%type;
wartosc TABLE2.value%type;
begin
open doupdate;
loop
fetch doupdate into nazwa,wartosc;
exit when doupdate%notfound;
update table1 set nazwa=wartosc;
end loop;
end;
While trying to run that code I got an error message which says:
PL/SQL: ORA-00904: "NAZWA": niepoprawny identyfikator
ORA-06550: linia 12, kolumna 1:
PL/SQL: SQL Statement ignored
What I'm doing wrong? Same types of columns - Varchar2(200 bytes)
Edit. there is a problem only with NAME... Anyone know the solution?...
EDIT2. I dit it and it works fine. I used dynamically SQL so it looks like: execute immediate 'update acc SET '||nazwa||'='||wartosc; . Could anyone explain why that?:)

This is dynamic sql, you have to execute it with Execute immediate command:
declare
cursor doupdate
is
select columnname,value from TABLE2;
nazwa TABLE2.columnname%type;
wartosc TABLE2.value%type;
dyn_sql varchar2(500);
begin
open doupdate;
loop
fetch doupdate into nazwa,wartosc;
exit when doupdate%notfound;
dyn_sql := 'update table1 set ' || nazwa || '=' ||wartosc;
execute immediate dyn_sql
end loop;
end;
Edit
A for loop and using clause will make things much simpler.
declare
dyn_sql varchar2(500);
begin
for i in (select columnname,value from TABLE2) loop
dyn_sql := 'update table1 set ' || i.columnname || ' = :a';
execute immediate dyn_sql using i.value
end loop;
end;
bind variable (execute immediate/using) will solve your problem of smth, smth2 and 'smth, smth2'

Do you have a column named 'nazwa' in table1?
If you don't have, that will be the problem.
If you have, I guess that confuses the Oracle server, because it can't decide whether you think about that column or the variable named nazwa in your code. In that case you should choose another name for your variable.
Edit: maybe you're missing WHERE clause from you UPDATE.

Related

PL\SQL - Get counts of all tables in a schema - errors

I want to get a result: table name, count amount for each table from AS_TABLE_LIST.
create procedure AtRowCount
as
declare
TableCount NUMBER(1);
TableName VARCHAR2(100);
BEGIN
SelectQuery1:= 'SELECT count(*) FROM ' || TableName || ' INTO ' || TableCount;
FOR TableName IN (select table_name from AS_TABLE_LIST)
LOOP
EXECUTE IMMEDIATE SelectQuery1;
END LOOP;
select TableName, TableCount into AT_ROW_COUNT from dual;
END AtRowCount;
I get two errors:
[Error] PLS-00306 (7: 19): PLS-00306: wrong number or types of
arguments in call to '||'
[Error] ORA-00904 (9: 8): PL/SQL: ORA-00904: "TABLENAME": invalid
identifier
I've been trying many times to fix this but still got same errors.
any advice?
I'm not exactly sure what you're trying todo, but it might be the following:
CREATE PROCEDURE AtRowCount AS
DECLARE
l_count NUMBER;
BEGIN
FOR c IN (SELECT table_name from AS_TABLE_LIST) LOOP
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM '||c.table_name INTO l_count;
INSERT INTO AT_ROW_COUNT(TableName, TableCount )
VALUES (c.table_name, l_count);
END LOOP;
END AtRowCount;
If you want you're procedure to return the list instead of inserting the result in a new table, you have to use a pipelined function instead (see https://oracle-base.com/articles/misc/pipelined-table-functions for an example on how to use it).
You can get all rows count against table name in oracle by:
select owner, table_name, nvl(num_rows,-1)
from all_tables
order by nvl(num_rows,-1) desc
https://livesql.oracle.com/apex/livesql/file/content_EPJLBHYMPOPAGL9PQAV7XH14Q.html
Hope this will work for you
CREATE PROCEDURE atrowcount
IS
selectquery1 VARCHAR2(2000);
tablecount NUMBER;
BEGIN
selectquery1:= 'SELECT count(1) FROM :TableName';
FOR i IN (select table_name from AS_TABLE_LIST)
LOOP
EXECUTE IMMEDIATE selectquery1 INTO tablecount USING i.table_name;
INSERT INTO table_list VALUES(i.table_name,TableCount);
END LOOP;
COMMIT;
END AtRowCount;

How to use dynamic where clause in EXECUTE IMMEDIATE

I have a table with columns insert,select,where clause,dynamic where clause,group by clause.
Using procedure i need to execute insert into statement and also use dynamic where clause.
I tried the following one however it is giving me an error missing expression.
create or replace PROCEDURE dynamicWhereClause(Datee IN DATE,processId IN NUMBER)
IS
processName VARCHAR2(100);
tablePrefix CONFIG_DETAILS.SOURCE_TABLE%Type;
sourceTableType CONFIG_DETAILS.SOURCE_TABLE_TYPE%Type;
insertClause CONFIG_DETAILS.INSERT_CLAUSE%Type;
selectClause CONFIG_DETAILS.SELECT_CLAUSE%Type;
whereClause CONFIG_DETAILS.WHERE_CLAUSE%Type;
onUpdateClause CONFIG_DETAILS.ON_UPDATE_CLAUSE%Type;
groupByClause CONFIG_DETAILS.GROUP_BY_CLAUSE%Type;
orderByClause CONFIG_DETAILS.ORDER_BY_CLAUSE%Type;
isDynamicWhereClause CONFIG_DETAILS.IS_DYNAMIC_WHERE_CLAUSE%Type;
tableName VARCHAR2(50);
Process_Date DATE;
processQuery VARCHAR2(6000 BYTE);
CURSOR Process_Report IS
select NAME,SOURCE_TABLE,SOURCE_TABLE_TYPE,INSERT_CLAUSE,SELECT_CLAUSE,WHERE_CLAUSE,ON_UPDATE_CLAUSE,GROUP_BY_CLAUSE,ORDER_BY_CLAUSE,IS_DYNAMIC_WHERE_CLAUSE FROM
CONFIG_DETAILS where ID=processId;
BEGIN
OPEN Process_Report;
LOOP
FETCH Process_Report INTO processName,tablePrefix,sourceTableType,insertClause,selectClause,whereClause,onUpdateClause,groupByClause,orderByClause,isDynamicWhereClause;
EXIT when Process_Report%NOTFOUND;
tableName := getSourceTableName(tablePrefix,sourceTableType,processDate);
Process_Date := processDate;
processQuery := insertClause || selectClause ||' from ' || tableName ||' ' ||
nvl(whereClause,'') ||''||nvl(groupByClause,'') ||''||nvl(orderByClause,'') ||''||nvl(onUpdateClause,'');
dbms_output.put_line(processQuery);
IF isDynamicWhereClause = 'Y'
THEN
dbms_output.put_line(processQuery);
EXECUTE IMMEDIATE processQuery USING Process_Date;
ELSE
EXECUTE IMMEDIATE processQuery;
END IF;
END LOOP;
CLOSE Process_Report;
END;
While executing the proc it is giving me the below error.
Error report -
ORA-00936: missing expression
ORA-06512: at "Mytest.dynamicWhereClause", line 44
ORA-06512: at line 1
00936. 00000 - "missing expression"
Please assist me further
Thanks
Your questions is not 100% clear . you saying after DATEE is being empty, are you assigning a variable after date ? the below is example of how using execute immediate with a variable. Note how is the bind variable :i is showing in the print.
set serveroutput on size 1000
/
declare t number(4) :=10;
txt varchar2(100);
begin
txt :='INSERT INTO TAB (ID) values (:i)';
dbms_output.put_line(t || ' ' || txt);
execute immediate txt using T;
end;
/
PL/SQL procedure successfully completed
10 INSERT INTO TAB (ID) values (:i)

PL/SQL Procedure Use String Select Statement in for loop

I am building a procedure, where I`m first creating a select statement and store it in an VARCAHR variable.
I now want to execute that query and store the whole result set in an variable to loop through it or use directly in a for loop.
I only find examples where the Select is hard written in the for loop definition.
How do i exchange the Select statement with my variable that holds my select statement?
for r IN (SELECT ... FROM ...)
loop
--do sth;
end loop;
how i want to use it :
statement := 'SELECT .... FROM ...';
for r IN (statement) -- HOW TO DO THIS
loop
--do sth;
end loop;
For a dynamic ref cursor, you need to define everything explicitly:
declare
sqlstring long := 'select 123 as id, ''demo'' as somevalue from dual where dummy = :b1';
resultset sys_refcursor;
type demo_rectype is record
( id integer
, somevalue varchar2(30) );
demorec demo_rectype;
begin
open resultset for sqlstring using 'X';
loop
fetch resultset into demorec;
exit when resultset%notfound;
dbms_output.put_line('id=' || demorec.id || ' somevalue=' || demorec.somevalue);
end loop;
close resultset;
end;
You can parse the cursor and figure out the column names and datatypes with DBMS_SQL. Example here: www.williamrobertson.net/documents/refcursor-to-csv.shtml

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') ;

DB2 dynamic table name

I want to count the rows of a number of tables. But the table name should be used dynamically. I want to do that within one SQL statement.
I tried it with
BEGIN ATOMIC
FOR tmp AS (
SELECT tabschema || '.' || tabname tbl
FROM syscat.tables WHERE tabname LIKE '%CD') DO
(SELECT COUNT(*) FROM tmp.tbl);
END FOR;
END
but I receive the error
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0204N "TMP.TBL" is an undefined name. LINE NUMBER=1. SQLSTATE=42704
and found no other working solution...
Is there a solution for that?
Thanks in advance.
I assume that your SELECT COUNT(*) FROM tmp.tbl should translate in multiple statements like
select count(*) from TABLECD
select count(*) from TABLE2CD
...
However, your query will try to do a count of the table TBL in the schema TMP.
You'll have to prepare the complete SQL statement, store it in a variable and pass it to the PREPARE statement (documentation ).
A rather complete stored procedure which somewhat fits your requirements can be found here . The result of the counts will be stored in a table COUNTERS which you can query afterwards.
//edit: this is the example from the topic, adapt to work (not tested since I have no DB2 instance to test atm):
CREATE PROCEDURE tableCount()
LANGUAGE SQL
BEGIN
DECLARE SQLCODE INTEGER DEFAULT 0;
DECLARE SQLSTATE CHAR(5);
DECLARE vTableName VARCHAR(20);
DECLARE vTableCount INTEGER;
DECLARE stmt varchar(2000);
DECLARE not_found CONDITION FOR SQLSTATE '02000';
DECLARE c1 CURSOR FOR
SELECT tabname from syscat.tables where tabschema='DB2ADMIN';
DECLARE C2 CURSOR FOR S2
DECLARE CONTINUE HANDLER FOR not_found
SET stmt = '';
Delete from COUNTERS;
OPEN c1;
getRows:
LOOP
FETCH c1 INTO vTableName;
IF SQLCODE = 0 THEN
SET stmt ='SELECT Count(*) FROM ' || vTableName;
PREPARE S2 FROM stmt;
OPEN C2;
SET vTableCount = 0;
FETCH C2 INTO vTableCount;
INSERT INTO COUNTERS (tableName, tableCount)
VALUES (vTableName, vTableCount);
CLOSE C2;
ELSE
LEAVE getRows;
END IF;
END LOOP getRows;
CLOSE c1;
END