How can I implement conditional updating in Oracle? - oracle

I'm new to oracle and having a problem with one of my SQL Queries.
There are 2 Users: User1 and User2:
Tab1 Tab2
-------- --------
EmpNo EmpNo
EmpName EmpName
ContactNo Salary
Location
User2 has all privileges in User1.Tab1, and there is no foreign key relationship between the two tables.
The Problem:
I wanted to add a column in tab2 "NameDesignation" And I wanted to insert the value in this column after checking the following condition:
WHEN User1.Tab1.EmpNo = User2.Tab2.EmpNo THEN
INSERT INTO Tab2 VALUES (&designation)
I really have no idea how to do this, and was hoping for a little help. Any thoughts?

try this:
update user2.tab2.empno t2
set NameDesignation= &designation
where exists (select ''
from user1.tab1 t1
where t1.empno=t2.empno)
(statement updated to match the edited question)

You would need a set of triggers,
After insert or update:
CREATE OR REPLACE TRIGGER tab1_after_changed
AFTER INSERT OR UPDATE
ON tab1
FOR EACH ROW
BEGIN
DELETE FROM User2.Tab2 WHERE EmpNo=:NEW.EmpNo;
INSERT INTO User2.Tab2(EmpNo,EmpName,NameDesignation)
VALUES (:NEW.EmpNo,:NEW.EmpName, (SELECT DesignationName FROM Designation where DesignationID=:NEW.DesignationID));
END;
I just imagined a table with Designation (DesignationID number, DesignationName varchar2(xx)), and Tab1 having DesignationID(number).

Related

select from the table name values after _ using oracle sql

Suppose if the table name is ABC_XYZ_123. I want to extract the integer values after _.
The output should be integer values after _.
In the above case, the output should be 123.
I have used the below sql query.
select from table_name like 'XXX_%';
But I am not getting required output. Can anyone help me with this query.
Thanks
Using REGEXP_SUBSTR with a capture group we can try:
SELECT REGEXP_SUBSTR(name, '_(\d+)$', 1, 1, NULL, 1)
FROM yourTable;
The question is somewhat unclear:
it looks as if you're looking for table names that contain number at the end, while
query you posted suggests that you're trying to select those numbers from one of table's columns
I'll stick to
Suppose if the table name is ABC_XYZ_123
If that's so, it is the data dictionary you'll query. USER_TABLES contains that information.
Let's create that table:
SQL> create table abc_xyz_123 (id number);
Table created.
Query selects numbers at the end of table names, for all my tables that end with numbers.
SQL> select table_name,
2 regexp_substr(table_name, '\d+$') result
3 from user_tables
4 where regexp_like(table_name, '\d+$');
TABLE_NAME RESULT
-------------------- ----------
TABLE1 1
TABLE2 2
restore_point-001 001
ABC_XYZ_123 123 --> here's your table
SQL>
Apparently, I have a few of them.

ORACLE avg,max,min salary TRIGGER

so i'm trying to create a trigger, but always have an error that says
Trigger LOG_SALARY compiled
LINE/COL ERROR
--------- ------------------------------------------------------------- 2/2 PL/SQL: SQL Statement ignored 3/9 PL/SQL: ORA-00934: group
function is not allowed here Errors: check compiler log
Error(2,2):PL/SQL: SQL Statement ignored
Error(3,9):PL/SQL:ORA-00934:group function is not allowed here
this is my code
'''alter table department add AVG_SALARY number(10);
alter table department add MAX_SALARY number(10);
alter table department add MIN_SALARY number(10);
insert into department (AVG_SALARY, MAX_SALARY, MIN_SALARY) values (AVG(salary), MAX(salary) ,MIN(salary));
create or replace TRIGGER log_salary
after update of salary on employee
for each row
begin
insert into DEPARTMENT(AVG_SALARY, MAX_SALARY, MIN_SALARY)
values(AVG(SALARY),MAX(SALARY),MIN(SALARY));
end;
update department
set salary = salary + 100.0
where SSN =888665555;
select * from DEPARTMENT;'''
could you tell me what is wrong with my code?
thankyou in advance!
You are inserting new rows into the department table. I think you want to update them. The logic looks like this:
create or replace TRIGGER log_salary
after update of salary on employee
for each row
begin
update department
set (AVG_SALARY, MAX_SALARY, MIN_SALARY) =
(select AVG(SALARY), MAX(SALARY), MIN(SALARY)
from employee
where e.department_id = :new.department_id
end;
This however will probably generate a mutating table error. Addressing that is really difficult. For instance, consider this:
emp_id dept_id salary
1 1 10
2 1 10
3 1 5
If you change emp_id's salary to 20, then the max is 20. But if you change the salary to 5, then the max remains 10.
I would suggest that you just use a view to calculate the values on-the-fly.

Automatically inserting data into a table using a procedure

I would like to ask you a rather easy question but I cannot get my head around it as I am a beginner in SQL.
My task is: Enter initial data into BankStats2 by inserting rows into BankStats2 that
contain the branch names together with how many loans are in the Loan
table for that branch name.
desc BankStats2
Name Null? Type
----------------------------------------- -------- ----------------------------
BRANCHNAME NOT NULL VARCHAR2(20)
NUMBEROFLOANS NUMBER(38)
desc Loan
Name Null? Type
----------------------------------------- -------- ----------------------------
CUSTOMERNAME CHAR(20)
BRANCHNAME CHAR(20)
AMOUNT NUMBER(38)
LOANNUMBER NOT NULL NUMBER(38)
select branchName,count(customerName) from Loan group by branchName;
BRANCHNAME COUNT(CUSTOMERNAME)
-------------------- -------------------
Yorkshire 3
RoyalBank 1
Midlands 3
Basically, I would like to insert this information in the BankStats2 table and the way I thought of doing it is by creating a procedure which I will show below.
CREATE OR REPLACE PROCEDURE PopulateBankStats AS
CURSOR someLoanRows IS
SELECT branchName,COUNT(customerName) FROM loan GROUP BY branchName;
aBranchNameRow loan.branchName%TYPE;
numberOfLoans INT;
BEGIN
OPEN someLoanRows;
LOOP
FETCH someLoanRows INTO aBranchNameRow, numberOfLoans;
INSERT INTO BankStats2 VALUES (aBranchNameRow,numberOfLoans);
EXIT WHEN someLoanRows%NOTFOUND;
END LOOP;
CLOSE someLoanRows;
END;
/
But executing it give me the following error:
ERROR at line 1:
ORA-00001: unique constraint (N0757934.SYS_C0034405) violated
ORA-06512: at "N0757934.POPULATEBANKSTATS", line 10
ORA-06512: at line 1
Any help would be greatly appreciated. Thank you for your time!
This insert fails: INSERT INTO BankStats2 VALUES (aBranchNameRow,numberOfLoans); due to the error: ORA-00001: unique constraint (N0757934.SYS_C0034405) violated
This means that there is an unique constraint created on some of the columns of the table BankStats2.
In order to find which column has unique constraint, run this query:
select * from USER_IND_COLUMNS where index_name = 'SYS_C0034405';
Your procedure is trying to insert a record with a value of this column which already is existing in the table.
Have a look on the INSERT statement.
What your procedure is doing is exactly this insert statement:
INSERT INTO BankStats2 (BRANCHNAME,NUMBEROFLOANS)
SELECT branchName,COUNT(customerName) FROM loan GROUP BY branchName;
It is always preferable to use SQL statement (if possible) instead of the PL/SQL cursor loop logik - search Tom Kyte's "row by row - slow by slow" for an explantion.
Even if you want to use a procedure at all cost - use this INSERT in the preocedure.
Your exception means that you try to insert a value of the column BRANCHNAME that already exists in the table BankStats2.
This could be by an accident or a systematic problem.
If it is an accident, simple clean the data, i.e. DELETE the row(s) with the corresponding keys from the BankStats2 table.
This query returns the values existing in both tables
select BRANCHNAME from BankStats2
intersect
select branchName FROM loan;
If you want to systematically avoid inserting the duplicated row, add this logik in your INSERT statement:
INSERT INTO BankStats2 (BRANCHNAME,NUMBEROFLOANS)
SELECT branchName,COUNT(customerName)
FROM loan
WHERE branchName IS NOT NULL
and branchName NOT IN (select BRANCHNAME from BankStats2)
GROUP BY branchName;
Note that the SELECT excludes the row with the value that already exists in the target table - using NOT IN (subquery).
Note also that I'm approaching your next possible problem. The column BRANCHNAME is non nullable in BankStats2, but is nullable (i.e. may contain NULL) in loan, so you would fail to insert the row with NULL to the table BankStats2. Therefore I exclude those rows with the branchName IS NOT NULL predicate.
If you want to process the existing keys with an UPDATE logik, check the MERGE statement.

Hive multiple insert goes wrong with the DISTINCT select statement

I read this code from "Hadoop the Definitive Guide":
SELECT a.ad_id, a.campaign_id, a.account_id, b.user_id
FROM dim_ads a JOIN impression_logs b ON (b.ad_id = a.ad_id)
WHERE b.dateid = '2008-12-01') x
INSERT OVERWRITE DIRECTORY 'results_gby_adid'
SELECT x.ad_id, count(1), count(DISTINCT x.user_id) GROUP BY x.ad_id
INSERT OVERWRITE DIRECTORY 'results_gby_campaignid'
SELECT x.campaign_id, count(1), count(DISTINCT x.user_id) GROUP BY x.campaign_id
INSERT OVERWRITE DIRECTORY 'results_gby_accountid'
SELECT x.account_id, count(1), count(DISTINCT x.user_id) GROUP BY x.account_id;
but as my test, using several DISTINCT cannot get right results.
my hiveql as below:
CREATE TABLE IF NOT EXISTS a (logindate int, id int);
then
load local file to this table...
CREATE TABLE IF NOT EXISTS user (id INT) PARTITIONED BY (logindate INT) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE;
then
if inserting table separately:
INSERT OVERWRITE TABLE user PARTITION(logindate=20130120) SELECT DISTINCT(id) FROM a WHERE logindate=20130120;
INSERT OVERWRITE TABLE user PARTITION(logindate=20130121) SELECT DISTINCT(id) FROM a WHERE logindate=20130121;
the results are correct;
but if choosing the next multiple insert hql:
FROM a
INSERT OVERWRITE TABLE user PARTITION(logindate=20130120) SELECT DISTINCT(id) WHERE logindate=20130120
INSERT OVERWRITE TABLE user PARTITION(logindate=20130121) SELECT DISTINCT(id) WHERE logindate=20130121;
the results are not correct, both partitions have the same number of records, seems like select from DISTINCT(id) WHERE logindate=20130120 OR logindate=20130121
so is it a bug or did I write some wrong syntax?
DISTINCT has a bit of an odd history in the code as an alias to group by.
If there is a bug, then the version of hive you are using would be important to know since bugs are addressed in each release.
This might work:
FROM a
INSERT OVERWRITE TABLE user PARTITION(logindate=20130120) SELECT id WHERE logindate=20130120 GROUP BY id
INSERT OVERWRITE TABLE user PARTITION(logindate=20130121) SELECT id WHERE logindate=20130121 GROUP BY id;
if that doesn't work, this will definitely work...even though it isn't the approach you were attempting to use...
FROM (select distinct id, logindate from a where logindate in ('20130120','20130121')) subq_a
INSERT OVERWRITE TABLE user PARTITION(logindate=20130120) SELECT id WHERE logindate=20130120
INSERT OVERWRITE TABLE user PARTITION(logindate=20130120) SELECT id WHERE logindate=20130121;

Oracle Inserting or Updating a row through a procedure

I have a table
CREATE TABLE STUDENT
(
ID INTEGER PRIMARY KEY,
FIRSTNAME VARCHAR2(1024 CHAR),
LASTNAME VARCHAR2(1024 CHAR),
MODIFIEDDATE DATE DEFAULT sysdate
)
I am inserting a row of data
insert into STUDENT (ID, FIRSTNAME, LASTNAME, MODIFIEDDATE) values (1,'Scott', 'Tiger', sysdate);
When I have to insert a record of data, I need to write a procedure or function which does the following:
if there is no record for the same id insert the row.
if there is a record for the same id and data matches then do nothing.
if there is a record for the same id but data does not match then update the data.
I am new to oracle. From the java end, It is possible to select the record by id and then update that record, but that would make 2 database calls. just to avoid that I am trying update the table using a procedure. If the same can be done in a single database call please mention.
For a single SQL statement solution, you can try to use the MERGE statement, as described in this answer https://stackoverflow.com/a/237328/176569
e.g.
create or replace procedure insert_or_update_student(
p_id number, p_firstname varchar2, p_lastname varchar2
) as
begin
merge into student st using dual on (id = p_id)
when not matched then insert (id, firstname, lastname)
values (p_id, p_firstname, p_lastname)
when matched then update set
firstname = p_firstname, lastname = p_lastname, modifiedate = SYSDATE
end insert_or_update_student;
instead of procedure try using merge in oracle .
If Values is matched it will update the table and if values is not found it will insert the values
MERGE INTO bonuses b
USING (
SELECT employee_id, salary, dept_no
FROM employee
WHERE dept_no =20) e
ON (b.employee_id = e.employee_id)
WHEN MATCHED THEN
UPDATE SET b.bonus = e.salary * 0.1
DELETE WHERE (e.salary < 40000)
WHEN NOT MATCHED THEN
INSERT (b.employee_id, b.bonus)
VALUES (e.employee_id, e.salary * 0.05)
WHERE (e.salary > 40000)
Try this
To solve the second task - "if there is a record for the same id and data matches then do nothing." - starting with 10g we have additional "where" clause in update and insert sections of merge operator.
To do the task we can add some checks for data changes:
when matched then update
set student.last_name = query.last_name
where student.last_name <> query.last_name
This will update only matched rows, and only for rows where data were changed

Resources