I want to update existing user names to following format user+(value of loop iterator) . Any advice? The current statement shows the value 'app2nd' after execution
UPDATE users
SET user_name = 'user'|| v_count
WHERE id = c_id;
Certainly, you should provide some more information. In the meantime, as I have some time to spare, two options for you: the first one doesn't require any loop (you mentioned) but utilizes the ROWNUM:
SQL> select * from test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> update test set
2 dname = 'user' || rownum --> this
3 where deptno >= 20;
3 rows updated.
SQL> select * From test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 user1 DALLAS
30 user2 CHICAGO
40 user3 BOSTON
SQL>
SQL> rollback;
Rollback complete.
SQL>
Another option, a LOOP I invented as you didn't explain which kind of a loop you have:
SQL> begin
2 for cur_r in (select deptno, dname,
3 row_number() over (order by deptno) rn
4 from dept)
5 loop
6 update test set
7 dname = 'user' || cur_r.rn
8 where deptno = cur_r.deptno;
9 end loop;
10 end;
11 /
PL/SQL procedure successfully completed.
SQL> select * From test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 user1 NEW YORK
20 user2 DALLAS
30 user3 CHICAGO
40 user4 BOSTON
SQL>
If it helps, fine. If not, you know what to do - express yourself in a poetic way.
Related
Structure of two tables in the database are as below.
1) Department table:
Dept_Id number(5) primary key,
Sept_Name varchar2(20),
Employee_strength number(4) not null.
2)Employee table:
E_Id number(5),
E_Name varchar2(20),
Designation varchar2(20),
D_ID number(5) references Department table Dept_ID.
A pl/sql program block to print the name the departments which has employees having the designation as "SE" is to be written and if no record in the department table fulfilling the given conditions found ,code should print the message "No record found" and if the record found code has to print Department name.
Please Help.
Here's one option (based on tables similar to yours; these belong to Scott).
I'll search for a SALESMAN.
SQL> break on deptno
SQL> select distinct d.deptno, e.job
2 from dept d left join emp e on e.deptno = d.deptno
3 order by d.deptno, e.job;
DEPTNO JOB
---------- ---------
10 CLERK
MANAGER
PRESIDENT
20 ANALYST
CLERK
MANAGER
30 CLERK
MANAGER
SALESMAN --> only department 30 has SALESMEN
40
10 rows selected.
SQL>
PL/SQL block:
SQL> set serveroutput on
SQL> declare
2 l_exists number(1);
3 begin
4 for cur_d in (select d.deptno, d.dname from dept d order by d.deptno) loop
5 select max(1)
6 into l_exists
7 from emp e
8 where e.deptno = cur_d.deptno
9 and e.job = 'SALESMAN';
10
11 dbms_output.put_line(cur_d.deptno || ' - ' ||
12 case when l_exists = 1 then cur_d.dname
13 else 'no record found'
14 end);
15 end loop;
16 end;
17 /
10 - no record found
20 - no record found
30 - SALES
40 - no record found
PL/SQL procedure successfully completed.
SQL>
If you want distinct department names then use the distinct() function in the SQL query.
I am using inner join to query the two table based on they have the same department id and department name is "SE".
Here are the steps to be followed:
declare the block(anonymous in this case)
write the SQL query for the cursor
begin the block
open the cursor
fetch the rows from the cursor
print the result
close the cursor
if the cursor doesn't contain any rows, so check for this condition
close the block
DECLARE
CURSOR C IS SELECT distinct(D.DEPT_NAME) FROM DEPARTMENTS D INNER JOIN EMPLOYEES E ON D.DEPT_ID = E.D_ID AND E.DESIGNATION LIKE 'SE';
RES C%ROWTYPE;
BEGIN
OPEN C;
loop
FETCH C INTO RES;
EXIT WHEN C%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(RES.DEPT_NAME);
end loop;
IF(C%ROWCOUNT=0) then
dbms_output.put_line('No record found');
end if;
END;
/
Write a PL/SQL program using While Loop to display all DEPTNO,DNAME and LOC
from DEPT table. Assuming the difference between two deptno is 10.
I am beginer and i am very confuse to solve this query please help to solve this problem.
Something like this?
SQL> set serveroutput on
SQL> declare
2 i dept.deptno%type; -- loop counter
3 l_max_deptno dept.deptno%type; -- upper limit
4 l_dept_row dept%rowtype; -- will contain the whole DEPT table row
5 begin
6 -- MIN -> i (which will be the starting point); MAX -> l_max_deptno (which will be the end)
7 select min(deptno), max(deptno)
8 into i, l_max_deptno
9 from dept;
10
11 while i <= l_max_deptno
12 loop
13 -- select the whole row into L_DEPT_ROW
14 select *
15 into l_dept_row
16 from dept
17 where deptno = i;
18
19 dbms_output.put_line(l_dept_row.deptno ||' - '||
20 l_dept_row.dname ||' - '||
21 l_dept_row.loc);
22 -- increment counter by 10 (because, as you said, the difference is 10)
23 i := i + 10;
24 end loop;
25 end;
26 /
10 - ACCOUNTING - NEW YORK
20 - RESEARCH - DALLAS
30 - SALES - CHICAGO
40 - OPERATIONS - BOSTON
PL/SQL procedure successfully completed.
SQL>
Here is how you do what you asked for, but bear in mind this is not the optimum way to do it. if your target is to train your self on the While loop in PLSQL, then here you go.
DECLARE
CURSOR C_DEPTS
IS
SELECT DEPTNO, DNAME, LOC FROM DEPT;
V_DEPTNO VARCHAR2 (255);
V_DNAME VARCHAR2 (255);
V_LOC VARCHAR2 (255);
BEGIN
OPEN C_DEPTS;
FETCH C_DEPTS INTO V_DEPTNO, V_DNAME, V_LOC;
WHILE C_DEPTS%FOUND
LOOP
DBMS_OUTPUT.PUT_LINE ('DEPTNO = ' || V_DEPTNO);
DBMS_OUTPUT.PUT_LINE ('DNAME = ' || V_DNAME);
DBMS_OUTPUT.PUT_LINE ('LOC = ' || V_LOC);
FETCH C_DEPTS INTO V_DEPTNO, V_DNAME, V_LOC;
END LOOP;
END;
I have a DB trigger before insert on emp table. I would like to add sal, comm from emp_test table and want to use those value as a default in the emp table, by trigger. Any idea how to do it?
Until you provide answers to questions I posted in a comment, here's how you might do it. See if you can adjust it.
EMP_TEST table contains only one row (which is kind of stupid; you'd rather use DEFAULT value for those columns in the EMP table).
SQL> create table emp_test (sal number, comm number);
Table created.
SQL> insert into emp_test (sal, comm) values (3000, 100);
1 row created.
Trigger takes SAL and COMM values if they are provided; otherwise, it takes values from the EMP_TEST table.
SQL> create or replace trigger trg_bi_emp
2 before insert on emp
3 for each row
4 begin
5 select nvl(:new.sal, t.sal),
6 nvl(:new.comm, t.comm)
7 into :new.sal,
8 :new.comm
9 from emp_test t;
10 end;
11 /
Trigger created.
Testing: I didn't provide SAL value (so trigger will insert EMP_TEST one), but I did provide COMM:
SQL> insert into emp (empno, ename, deptno, sal, comm)
2 values (1, 'Littlefoot', 40, null, 50);
1 row created.
SQL> select * from emp where empno = 1;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
1 Littlefoot 3000 50 40
SQL>
I have a procedure which should return 3 dept names and update the start time for these three dept names. This script will be run by parallel threads.
I tried to achieve it using cursors but not returning the result.
Table with inserts:
create table dept (sno number(4), deptname varchar2(40), start_time date)
insert into dept values(1,'DEPT1',NULL);
insert into dept values(1,'DEPT2',NULL);
insert into dept values(1,'DEPT3',NULL);
insert into dept values(2,'DEPT4',NULL);
insert into dept values(2,'DEPT5',NULL);
insert into dept values(2,'DEPT6',NULL);
Approach 1:
TYPE deptname IS RECORD(op_deptname dept.deptname%TYPE);
TYPE cursor_deptname IS REF CURSOR RETURN deptname;
CREATE OR REPLACE PROCEDURE get_deptname(ip_sno IN dept.sno%TYPE, op_cursor OUT cursor_deptname);
IS
vv_dept_name dept.deptname%type;
BEGIN
LOCK TABLE dept IN EXCLUSIVE MODE;
OPEN op_cursor FOR
SELECT deptname
FROM dept
WHERE sno = ip_sno
AND start_time IS NULL
AND ROWNUM <= 3;
LOOP
FETCH op_cursor INTO vv_dept_name;
EXIT WHEN op_cursor%NOTFOUND;
UPDATE dept
SET start_time = sysdate
WHERE deptname = vv_dept_name;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
IF op_cursor%ISOPEN THEN CLOSE op_cursor; END IF;
END;
Proc execution from application.
DECLARE
i deptname;
c_cursor cursor_deptname;
BEGIN
get_deptname(2,c_cursor);
LOOP
FETCH c_cursor INTO i;
DBMS_OUTPUT.PUT_LINE('name:'||i.op_deptname);
EXIT WHEN c_cursor %NOTFOUND;
END LOOP;
END;
With this approach I'm able to update the table with date but dept names are not retrieved in the cursor.
Here's how I understood the question.
Table contents:
SQL> select * from tdept;
SNO DEPTNAME START_TIME
---------- ---------------------------------------- ----------
1 DEPT1
1 DEPT2
1 DEPT3
2 DEPT4
2 DEPT5
2 DEPT6
6 rows selected.
The procedure, which
updates the table
returns refcursor
SQL> create or replace procedure get_deptname
2 (ip_sno in tdept.sno%type,
3 op_cursor out sys_refcursor
4 )
5 is
6 begin
7 update tdept t set
8 t.start_time = sysdate
9 where t.sno = ip_sno;
10
11 open op_cursor for
12 select deptname
13 from tdept
14 where sno = ip_sno;
15 end;
16 /
Procedure created.
Execution & the result:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> var lout refcursor
SQL>
SQL> exec get_deptname(2, :lout);
PL/SQL procedure successfully completed.
SQL> select * from tdept;
SNO DEPTNAME START_TIME
---------- ---------------------------------------- -------------------
1 DEPT1
1 DEPT2
1 DEPT3
2 DEPT4 10.04.2018 20:32:23
2 DEPT5 10.04.2018 20:32:23
2 DEPT6 10.04.2018 20:32:23
6 rows selected.
SQL> print lout
DEPTNAME
----------------------------------------
DEPT4
DEPT5
DEPT6
SQL>
I have a list of 9 digit IDs in a table I called "numbers", with one column called "ID". I want to use those in a subquery to look for specific rows in a table called artransaction. The problem is that in the transactionid column in artransaction, it has a zero in front of the 9 digit ID.
So if I do:
select * from artransaction
where transactionid in lpad((select id from numbers where rownum=1),10,'0');
It comes back with a result. But if I do:
select * from artransaction
where transactionid in lpad((select id from numbers),10,'0');
It says "single-row subquery returns more than one row"
Is it possible to put in a subquery in LPAD?
You should rewrite that query. Here's an example based on Scott's EMP table - I want to select rows that contain COMM which looks like the ones stored in the NUMBERS table.
SQL> select ename, comm from emp order by ename;
ENAME COMM
---------- ----------
ALLEN 300
BLAKE
CLARK
FORD
JAMES
JONES
KING
MARTIN 1400
MILLER
SMITH
TURNER 0
WARD 500
12 rows selected.
SQL>
Sample NUMBERS table:
SQL> create table numbers (comm number);
Table created.
SQL> insert into numbers values (14);
1 row created.
SQL> insert into numbers values (50);
1 row created.
SQL> insert into numbers values (3);
1 row created.
SQL> select * From numbers;
COMM
----------
14
50
3
SQL>
Testing:
SQL> -- This one will work because of the ROWNUM = 1 condition, which returns a single value
SQL> select * from emp
2 where comm in rpad((select comm from numbers where rownum = 1), 4, '0');
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
7654 MARTIN SALESMAN 7698 28.09.1981 1250 1400 30
SQL> -- This will result in error because NUMBERS contain several values
SQL> select * from emp
2 where comm in rpad((select comm from numbers), 4, '0');
where comm in rpad((select comm from numbers), 4, '0')
*
ERROR at line 2:
ORA-01427: single-row subquery returns more than one row
SQL> -- So - rewrite it
SQL> select * from emp
2 where comm in (select rpad(comm, 3, '0') from numbers);
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
7521 WARD SALESMAN 7698 22.02.1981 1250 500 30
7499 ALLEN SALESMAN 7698 20.02.1981 1600 300 30
SQL>
Or, applied to your query:
select * from artransaction
where transactionid in (select lpad(id, 10, '0') from numbers);