Oracle SQL - Remove Null rows in aliased results - oracle

Hi devs I'm developing a small pro bono project that's use oracle sql but I'm not able to hide the null results.
Table Structure:
CREATE TABLE "church-members" (
ID NUMBER(10),
NAME varchar(30) NOT NULL,
LOGIN varchar(20) NOT NULL,
PASS varchar(12) NOT NULL,
REGISTER_YEAR_MONTH varchar(15) NOT NULL,
USER_SCORE NUMBER(10),
PRIMARY KEY (ID));
The queries:
INSERT INTO "church-members" VALUES
('1', 'John Doe', 'John', 'Xo8*d_d%f58*', '202204','1');
INSERT INTO "church-members" VALUES
('2', 'Mary Doe', 'Mary', 'dLoc&257dsew', '202203','2');
INSERT INTO "church-members" VALUES
('3', 'Robertson III', 'Robertson', 'koIIf59*Liu*', '202203','7');
INSERT INTO "church-members" VALUES
('4', 'Sonia MacDonald', 'Sonia', 'fYhfgtdjfi%', '202204','4');
INSERT INTO "church-members" VALUES
('5', 'Boris Johnston', 'Boris', 'do*&flddkIK%', '202201','2');
INSERT INTO "church-members" VALUES
('6', 'Ruth Henderson', 'Ruth', 'dF6%*&', '202202','2');
The Select:
SELECT
ID,
NAME,
LOGIN,
MAX(CASE WHEN REGISTER_YEAR_MONTH = '202203' THEN TO_CHAR(USER_SCORE) ELSE '' END) AS "MARCH SCORE",
MAX(CASE WHEN REGISTER_YEAR_MONTH = '202204' THEN TO_CHAR(USER_SCORE) ELSE '' END) AS "APRIL SCORE "
FROM
"church-members"
GROUP BY
ID,
NAME,
LOGIN
And the result fiddle:
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=a4deac5e3eefb17dca97661552458a61
I got to this point using the information obtained in the answer from this link:
Select more than one column and remove NULL values from result
Looking at the fiddle example, the results with IDs 5 and 6 should not be showing because both are nulls.
But still null results are being shown...
Can anyone help me to solve it?

Add a HAVING clause requiring that each matching ID have at least data for at least one of the two months:
SELECT ID, NAME, LOGIN,
MAX(CASE WHEN REGISTER_YEAR_MONTH = '202203' THEN TO_CHAR(USER_SCORE) END) AS "MARCH SCORE",
MAX(CASE WHEN REGISTER_YEAR_MONTH = '202204' THEN TO_CHAR(USER_SCORE) END) AS "APRIL SCORE"
FROM "church-members"
GROUP BY ID, NAME, LOGIN
HAVING COUNT(CASE WHEN REGISTER_YEAR_MONTH IN ('202203', '202204') THEN 1 END) > 0;

Related

Insert statement and create table oracle

My tables are been created, but when I am trying to put the insert statements it's giving me an error saying parent not found.
This is my create table:
Create table patient (
Patient_ID Number(9) primary key,
First_name varchar2(15),
Last_name varchar2(10),
Contact number(10),
City varchar2(20),
Doctor_ID Number(9) references Doctor(Doctor_ID)
);
This is the insert statement:
insert into patient (Patient_ID, First_name, Last_name, Contact, City, Doctor_ID) values ('21345', 'John', 'Smith', '1111111111', 'NY', '30111');
Try :
insert into patient (Patient_ID, First_name, Last_name, Contact, City, Doctor_ID) values (21345, 'John', 'Smith', 1111111111, 'NY', 30111);
Don't use quotes for numbers.

Oracle : It give a error in a dynamic view

I have two table one is employee and one is department. I am creating the dynamic view that will rank all departments by salary. The view should pull information from Department and Employee, sum the salary by department, and rank the department by salary.
CREATE TABLE DEPARTMENT
(DEPARTMENT_ID NUMBER PRIMARY KEY,
DEPARTMENT_NAME VARCHAR(30) NOT NULL
);
CREATE TABLE JOBS
(JOB_ID NUMBER PRIMARY KEY,
JOB_TITLE VARCHAR(35) NOT NULL,
MIN_SALARY DECIMAL NOT NULL,
MAX_SALARY DECIMAL NOT NULL
);
CREATE TABLE EMPLOYEES
(EMPLOYEE_ID NUMBER PRIMARY KEY,
FIRST_NAME VARCHAR(20) NOT NULL,
LAST_NAME VARCHAR(25) NOT NULL,
EMAIL VARCHAR(25) NOT NULL,
PHONE_NUMBER VARCHAR(20) NOT NULL,
HIRE_DATE DATE NOT NULL,
JOB_ID NUMBER NOT NULL,
SALARY DECIMAL NOT NULL,
DEPARTMENT_ID NUMBER NOT NULL,
CONSTRAINT emp_job_fk FOREIGN KEY(JOB_ID) REFERENCES JOBS(JOB_ID),
CONSTRAINT emp_department_fk FOREIGN KEY(DEPARTMENT_ID) REFERENCES DEPARTMENT(DEPARTMENT_ID)
);
INSERT INTO DEPARTMENT (DEPARTMENT_ID,DEPARTMENT_NAME)
VALUES(1,'IT');
INSERT INTO DEPARTMENT (DEPARTMENT_ID,DEPARTMENT_NAME)
VALUES(2,'Sales');
INSERT INTO JOBS (JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY)
VALUES (1,'IT Administrator',250000.00,50000.00);
INSERT INTO JOBS (JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY)
VALUES (2,'Salesman',200000.00,40000.00);
Here is I create so far but it give me a error
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
*Cause:
*Action:
Error at Line: 4 Column: 9
Here is my code
select department_id,department_name,total_salary
from(
select department_id,department_name, SALARY, count(*) as total_salary from(
select dep.department_id , dep.department_name ,emp.SALARY,
DENSE_RANK() OVER (PARTITION BY department_name ORDER BY salary)
from departments dep
inner join employees emp on dep.DEPARTMENT_ID = emp.DEPARTMENT_ID
)
GROUP BY SALARY)
Your query needs to join EMPLOYEES (to get the salaries) to DEPARTMENT (to get the DEPARTMENT_NAME). Calculate the total salary for each department by summing the employee salaries, not counting them. The GROUP BY needs to include the non-aggregated columns.
Then you need to rank the departments by the total salary per department. This query ranks the departments with highest salary = 1. It uses a left join to cater for departments with no employees.
select department_id
, department_name
, total_salary
, rank() over (order by total_salary desc) as dept_rank
from (
select d.department_id
, d.department_name
, sum(e.SALARY) as total_salary
from department d
left join employees e
on e.department_id = d.department_id
group by d.department_id
, d.department_name
)
/

Case and Decode

I have written a query to display the customer id, login id and sum of credit debt amount of the customer. If the customer due amount is to be debited a virtual column must be created and display as Due from customer else Due to Customer. Please help me solve the query.
I am attaching the table Structure and values along with my query.
-- Customer Table
CREATE TABLE isbs_customer_mst
(
cust_id VARCHAR2(30) NOT NULL,
login_id VARCHAR2(30) NOT NULL,
cust_nm VARCHAR2(30),
cust_addr VARCHAR2(300),
CONSTRAINT isbs_customer_mst_pk PRIMARY KEY (cust_id)
);
--Values
INSERT INTO ISBS_CUSTOMER_MST (CUST_ID, LOGIN_ID, CUST_NM, CUST_ADDR)
VALUES ('CUST0000000001', 'USER1', 'User Login ID 1', '143/1 Uthamar Gandhi Salai, Nungambakkam, Chennai - 34');
INSERT INTO ISBS_CUSTOMER_MST (CUST_ID, LOGIN_ID, CUST_NM, CUST_ADDR)
VALUES ('CUST0000000002', 'USER2', 'User Login ID 2', '143/2 Uthamar Gandhi Salai, Nungambakkam, Chennai - 34');
INSERT INTO ISBS_CUSTOMER_MST (CUST_ID, LOGIN_ID, CUST_NM, CUST_ADDR)
VALUES ('CUST0000000003', 'USER3', 'User Login ID 3', '143/3 Uthamar Gandhi Salai, Nungambakkam, Chennai - 34');
INSERT INTO ISBS_CUSTOMER_MST (CUST_ID, LOGIN_ID, CUST_NM, CUST_ADDR)
VALUES ('CUST0000000004', 'USER4', 'User Login ID 4', '143/4 Uthamar Gandhi Salai, Nungambakkam, Chennai - 34');
--Credit Debit Table
CREATE TABLE isbs_acct_ledger_det
(
acct_ledger_id VARCHAR2(30),
cust_id VARCHAR2(30),
credit_debit_amt VARCHAR2(30) NOT NULL,
credit_debit_dttm TIMESTAMP NOT NULL,
CONSTRAINT isbs_acct_ledger_det_pk PRIMARY KEY (acct_ledger_id),
CONSTRAINT isbs_acct_ledger_det_fk FOREIGN KEY (cust_id) REFERENCES
isbs_customer_mst (cust_id)
);
-- Values
INSERT INTO ISBS_ACCT_LEDGER_DET (ACCT_LEDGER_ID, CUST_ID, CREDIT_DEBIT_AMT, CREDIT_DEBIT_DTTM)
VALUES ('ACC0000000001', 'CUST0000000001', -1000.25, TO_DATE('01-10-2008 11:00:00', 'DD-MM-YYYY HH24:MI:SS'));
INSERT INTO ISBS_ACCT_LEDGER_DET (ACCT_LEDGER_ID, CUST_ID, CREDIT_DEBIT_AMT, CREDIT_DEBIT_DTTM)
VALUES ('ACC0000000002', 'CUST0000000002', -256.75, TO_DATE('01-10-2008 11:00:00', 'DD-MM-YYYY HH24:MI:SS'));
INSERT INTO ISBS_ACCT_LEDGER_DET (ACCT_LEDGER_ID, CUST_ID, CREDIT_DEBIT_AMT, CREDIT_DEBIT_DTTM)
VALUES ('ACC0000000003', 'CUST0000000002', 100.25, TO_DATE('05-10-2008 11:00:00', 'DD-MM-YYYY HH24:MI:SS'));
-- Query
SELECT c.CUST_NM
, c.LOGIN_ID
, SUM(a.CREDIT_DEBIT_AMT) "Outstanding Amt"
, CASE WHEN a.CREDIT_DEBIT_AMT <= -9999.99
THEN 'Due to Cust'
ELSE 'Due from Cust' END "Due"
FROM ISBS_CUSTOMER_MST c
JOIN ISBS_ACCT_LEDGER_DET a
ON c.CUST_ID = a.CUST_ID
GROUP BY c.CUST_NM, c.LOGIN_ID, a.CREDIT_DEBIT_AMT;
Thanks in advance
You probably need to remove a.CREDIT_DEBIT_AMT from group by and use CASE expression on SUM().
SELECT c.cust_nm,
c.login_id,
SUM(a.credit_debit_amt) "Outstanding Amt",
CASE
WHEN SUM(a.credit_debit_amt) <= -9999.99 THEN 'Due to Cust'
ELSE 'Due from Cust'
END "Due"
FROM isbs_customer_mst c
JOIN isbs_acct_ledger_det a
ON c.cust_id = a.cust_id
GROUP BY c.cust_nm,
c.login_id ;
You need to add case statement in group by clause:
SELECT c.CUST_NM , c.LOGIN_ID , SUM(a.CREDIT_DEBIT_AMT) "Outstanding Amt" , CASE WHEN a.CREDIT_DEBIT_AMT <= -9999.99 THEN 'Due to Cust' ELSE 'Due from Cust' END "Due" FROM ISBS_CUSTOMER_MST c JOIN ISBS_ACCT_LEDGER_DET a ON c.CUST_ID = a.CUST_ID GROUP BY c.CUST_NM, c.LOGIN_ID, CASE WHEN a.CREDIT_DEBIT_AMT <= -9999.99 THEN 'Due to Cust' ELSE 'Due from Cust' END "Due";
As it is the rule of aggregate functions to have all other selected attributes in group by clause
Why would you use sin function when you are dealing with sum. Sin gives the sin value of the parameter
Whereas abs returns the positive number, likewise
Select abs(-5) from dual ;
Will return 5 as output.
I dont think your requirement needs both these functions.

How to implement this trigger on Oracle SQL?

I have found an exercise in the SQL book I study, which is not solved and I can not solve it.
The goal is to implement a trigger that avoids overlapping contracts. If a customer with a current contract signs a new one, the end date of the previous one will be one day before the new start date.
Tables given are:
CREATE TABLE CLIENTS (
clientId VARCHAR2(15),
DNI VARCHAR2(9),
name VARCHAR2(100) NOT NULL,
surname VARCHAR2(100) NOT NULL,
sec_surname VARCHAR2(100),
eMail VARCHAR2(100) NOT NULL,
phoneN NUMBER(12),
birthdate DATE,
CONSTRAINT PK_CLIENTS PRIMARY KEY (clientId),
CONSTRAINT UK1_CLIENTS UNIQUE (DNI),
CONSTRAINT UK2_CLIENTS UNIQUE (eMail),
CONSTRAINT UK3_CLIENTS UNIQUE (phoneN),
);
CREATE TABLE contracts(
contractId VARCHAR2(10),
clientId VARCHAR2(15),
startdate DATE NOT NULL,
enddate DATE,
contract_type VARCHAR2(50),
address VARCHAR2(100) NOT NULL,
town VARCHAR2(100) NOT NULL,
ZIPcode VARCHAR2(8) NOT NULL,
country VARCHAR2(100) NOT NULL,
CONSTRAINT PK_contracts PRIMARY KEY (contractId),
CONSTRAINT FK_contracts1 FOREIGN KEY (clientId) REFERENCES CLIENTS
);
Any suggestions?
I agree with the posted comments that it helps to have some specifics about what is failing in the prior attempts, and I would also recommend not using a TRIGGER at all for this kind of thing.
But as this is for a study exercise, here are some examples that might be a starting place.
I've modified your tables to disallow NULL PRIMARY KEYs in these examples.
To get started, create the tables:
CREATE TABLE CLIENTS (
CLIENTID VARCHAR2(15) NOT NULL,
DNI VARCHAR2(9),
NAME VARCHAR2(100) NOT NULL,
SURNAME VARCHAR2(100) NOT NULL,
SEC_SURNAME VARCHAR2(100),
EMAIL VARCHAR2(100) NOT NULL,
PHONEN NUMBER(12),
BIRTHDATE DATE,
CONSTRAINT PK_CLIENTS PRIMARY KEY (CLIENTID),
CONSTRAINT UK1_CLIENTS UNIQUE (DNI),
CONSTRAINT UK2_CLIENTS UNIQUE (EMAIL),
CONSTRAINT UK3_CLIENTS UNIQUE (PHONEN)
);
CREATE TABLE CONTRACTS (
CONTRACTID VARCHAR2(10) NOT NULL,
CLIENTID VARCHAR2(15) NOT NULL,
STARTDATE DATE NOT NULL,
ENDDATE DATE,
CONTRACT_TYPE VARCHAR2(50),
ADDRESS VARCHAR2(100) NOT NULL,
TOWN VARCHAR2(100) NOT NULL,
ZIPCODE VARCHAR2(8) NOT NULL,
COUNTRY VARCHAR2(100) NOT NULL,
CONSTRAINT PK_CONTRACTS PRIMARY KEY (CONTRACTID),
CONSTRAINT FK_CONTRACTS1 FOREIGN KEY (CLIENTID) REFERENCES CLIENTS
);
Then, create the first CLIENTs:
INSERT INTO CLIENTS VALUES (1,NULL,'Frodo','Baggins',NULL,'the.real.frodo#adventure.com',NULL,NULL);
INSERT INTO CLIENTS VALUES (2,NULL,'Chewbacca','UNKNOWN',NULL,'chewio.#kashyyyk.org',NULL,NULL);
COMMIT;
Then create a TRIGGER. In this first example, the TRIGGER is an AFTER STATEMENT type.
It is simple but inefficient since it evaluates every CLIENT after each INSERT statement.
Against a large data set, or in the face of multiple TRIGGERs, this could be a problem.
This TRIGGER will check for the prior contract and will set its ENDDATE to one day before the new contract, if it is null or after the start of the new contract.
CREATE OR REPLACE TRIGGER CONTRACT_ENDDATE_ADJUSTER
AFTER INSERT ON CONTRACTS
BEGIN
MERGE INTO CONTRACTS
USING (
SELECT CONTRACTID,
CANDIDATE_ENDDATE AS ENDDATE
FROM
(SELECT CONTRACTS.CONTRACTID,
(TRUNC(LEAD(STARTDATE) OVER (PARTITION BY CLIENTID ORDER BY STARTDATE ASC) - 1)) AS CANDIDATE_ENDDATE,
DENSE_RANK() OVER (PARTITION BY CLIENTID ORDER BY STARTDATE DESC) AS CONTRACT_ORDER
FROM CONTRACTS)
WHERE CONTRACT_ORDER = 2) CANDIDATE_CONTRACT
ON (CONTRACTS.CONTRACTID = CANDIDATE_CONTRACT.CONTRACTID)
WHEN MATCHED THEN UPDATE SET CONTRACTS.ENDDATE = CANDIDATE_CONTRACT.ENDDATE
WHERE CONTRACTS.ENDDATE IS NULL OR CONTRACTS.ENDDATE > CANDIDATE_CONTRACT.ENDDATE;
END;
/
Then, test it out.
Add the initial contracts. No enddate changes expected, as these are the first. Frodo's contract here has an end-date already set.
INSERT INTO CONTRACTS VALUES('Break-Ring',1,TO_DATE('19560511','YYYYMMDD'), TO_DATE('19851014','YYYYMMDD'), NULL, 'No 1', 'Doom Mountain', 'MORD', 'Middle-Earth');
INSERT INTO CONTRACTS VALUES('SaveGalaxy',2,TO_DATE('19770615','YYYYMMDD'), NULL, NULL, 'No 75', 'Rwookrrorro', 'RWKR', 'Kashyyyk');
SELECT CONTRACTID, CLIENTID, STARTDATE, ENDDATE FROM CONTRACTS ORDER BY CLIENTID ASC, STARTDATE ASC;
CONTRACTID CLIENTID STARTDATE ENDDATE
Break-Ring 1 11-MAY-56 14-OCT-85
SaveGalaxy 2 15-JUN-77
Then add new contracts.
Frodo's new contract starts before the end of his existing contract, so the enddate will be adjusted.
Chewie's initial contract had no ENDDATE, so it will be adjusted as well.
INSERT INTO CONTRACTS VALUES('GoBackHome',1,TO_DATE('19570219','YYYYMMDD'), NULL, NULL, 'No 13', 'Hobbiton', 'HBTN', 'Middle-Earth');
INSERT INTO CONTRACTS VALUES('DefendHoth',2,TO_DATE('19801115','YYYYMMDD'), NULL, NULL, 'Meteor Crater', 'Ice Ridge', 'METEO', 'Hoth');
SELECT CONTRACTID, CLIENTID, STARTDATE, ENDDATE FROM CONTRACTS ORDER BY CLIENTID ASC, STARTDATE ASC;
CONTRACTID CLIENTID STARTDATE ENDDATE
Break-Ring 1 11-MAY-56 18-FEB-57
GoBackHome 1 19-FEB-57
SaveGalaxy 2 15-JUN-77 14-NOV-80
DefendHoth 2 15-NOV-80
And as other contracts are signed, the pattern continues:
INSERT INTO CONTRACTS VALUES('GoWedding',2,TO_DATE('19830309','YYYYMMDD'), NULL, NULL, 'Main Hall', 'Grand Palace', 'ALLNC', 'Coruscant');
INSERT INTO CONTRACTS VALUES('Gardening',1,TO_DATE('19570503','YYYYMMDD'), NULL, NULL, 'No 13', 'Hobbiton', 'HBTN', 'Middle-Earth');
SELECT CONTRACTID, CLIENTID, STARTDATE, ENDDATE FROM CONTRACTS ORDER BY CLIENTID ASC, STARTDATE ASC;
CONTRACTID CLIENTID STARTDATE ENDDATE
Break-Ring 1 11-MAY-56 18-FEB-57
GoBackHome 1 19-FEB-57 02-MAY-57
Gardening 1 03-MAY-57
SaveGalaxy 2 15-JUN-77 14-NOV-80
DefendHoth 2 15-NOV-80 08-MAR-83
GoWedding 2 09-MAR-83
To stabilize the workload on this query, a COMPOUND TRIGGER may be used instead. This second example achieves the same result as the first, but only interrogates the CONTRACTs of CLIENTs that have changed:
First, ROLLBACK;
Then, create a type to be used by the TRIGGER:
CREATE OR REPLACE TYPE NUMBER_LIST IS TABLE OF NUMBER;
/
Then create the COMPOUND TRIGGER:
CREATE OR REPLACE TRIGGER CONTRACT_ENDDATE_ADJUSTER
FOR INSERT ON CONTRACTS
COMPOUND TRIGGER
V_CLIENTS NUMBER_LIST;
BEFORE STATEMENT
IS
BEGIN
V_CLIENTS:= NUMBER_LIST();
END BEFORE STATEMENT;
AFTER EACH ROW
IS
BEGIN
V_CLIENTS.EXTEND();
V_CLIENTS(V_CLIENTS.COUNT) := :NEW.CLIENTID;
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
MERGE INTO CONTRACTS
USING (
SELECT CONTRACTID,
CANDIDATE_ENDDATE AS ENDDATE
FROM
(SELECT CONTRACTS.CONTRACTID,
(TRUNC(LEAD(STARTDATE) OVER (PARTITION BY CLIENTID ORDER BY STARTDATE ASC) - 1)) AS CANDIDATE_ENDDATE,
DENSE_RANK() OVER (PARTITION BY CLIENTID ORDER BY STARTDATE DESC) AS CONTRACT_ORDER
FROM CONTRACTS
WHERE CONTRACTS.CLIENTID IN (SELECT * FROM TABLE(V_CLIENTS)))
WHERE CONTRACT_ORDER = 2) CANDIDATE_CONTRACT
ON (CONTRACTS.CONTRACTID = CANDIDATE_CONTRACT.CONTRACTID)
WHEN MATCHED THEN UPDATE SET CONTRACTS.ENDDATE = CANDIDATE_CONTRACT.ENDDATE
WHERE CONTRACTS.ENDDATE IS NULL OR CONTRACTS.ENDDATE > CANDIDATE_CONTRACT.ENDDATE;
END AFTER STATEMENT;
END CONTRACT_ENDDATE_ADJUSTER;
/
After repeating the above inserts, the result is the same:
CONTRACTID CLIENTID STARTDATE ENDDATE
Break-Ring 1 11-MAY-56 18-FEB-57
GoBackHome 1 19-FEB-57 02-MAY-57
Gardening 1 03-MAY-57
SaveGalaxy 2 15-JUN-77 14-NOV-80
DefendHoth 2 15-NOV-80 08-MAR-83
GoWedding 2 09-MAR-83

How to Duplicate multiple rows (Oracle)

I'm trying to make a Procedure that will duplicate multiple rows of a table (or only one single row) and incrementing the ID for each row insertion.
My problem is that inside my procedure I used a cursor to select the rows to duplicate, when i select all rows without WHERE condition in that cursor everything works fine.
But when i set a WHERE condition to select only one row... nothing happens
Here is my procedure
CREATE OR REPLACE PROCEDURE DuplicateEmployee (p_EmployeeID IN Employee.id%TYPE)
AS
p_New_EmployeeID Employee.id%TYPE;
CURSOR c_DuplicateEmployee IS
SELECT *
FROM Employee
WHERE Employee.id = p_EmployeeID; -- if this line is deleted all content is duplicated
row_Employee c_DuplicateEmployee%ROWTYPE;
BEGIN
FOR myEmployee IN c_DuplicateEmployee LOOP
p_New_EmployeeID := employee_seq.NEXTVAL;
INSERT INTO Employee(id, first_name, last_name, start_date, end_date, salary, city, description)
VALUES(p_New_EmployeeID, myEmployee.first_name, myEmployee.last_name, myEmployee.start_date, myEmployee.end_date, myEmployee.salary, myEmployee.city, myEmployee.description);
END LOOP;
COMMIT;
END DuplicateEmployee;
I know in this example having a procedure selecting a primary key to duplicate is pointless but in my production base it will be used to select a Foreign key.
Bellow is the code require to create a the test table and SEQUENCE I used for this procedure
CREATE TABLE Employee
(
ID VARCHAR2(4 BYTE) NOT NULL,
First_Name VARCHAR2(10 BYTE),
Last_Name VARCHAR2(10 BYTE),
Start_Date DATE,
End_Date DATE,
Salary NUMBER(8,2),
City VARCHAR2(10 BYTE),
Description VARCHAR2(15 BYTE)
);
INSERT
INTO Employee
(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
('01', 'Jason', 'Martin', to_date('19960725','YYYYMMDD'), to_date('20060725','YYYYMMDD'), 1234.56, 'Toronto', 'Programmer');
INSERT
INTO Employee
(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
('02', 'Alison', 'Mathews', to_date('19760321','YYYYMMDD'), to_date('19860221','YYYYMMDD'), 6661.78, 'Vancouver', 'Tester');
INSERT
INTO Employee
(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
('03', 'James', 'Smith', to_date('19781212','YYYYMMDD'), to_date('19900315','YYYYMMDD'), 6544.78, 'Vancouver', 'Tester');
INSERT
INTO Employee
(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
('04', 'Celia', 'Rice', to_date('19821024','YYYYMMDD'), to_date('19990421','YYYYMMDD'), 2344.78, 'Vancouver', 'Manager');
INSERT
INTO Employee
(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
('05', 'Robert', 'Black', to_date('19840115','YYYYMMDD'), to_date('19980808','YYYYMMDD'), 2334.78, 'Vancouver', 'Tester');
INSERT
INTO Employee
(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
('06', 'Linda', 'Green', to_date('19870730','YYYYMMDD'), to_date('19960104','YYYYMMDD'), 4322.78, 'New York', 'Tester');
INSERT
INTO Employee
(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
('07', 'David', 'Larry', to_date('19901231','YYYYMMDD'), to_date('19980212','YYYYMMDD'), 7897.78, 'New York', 'Manager');
INSERT
INTO Employee
(ID, First_Name, Last_Name, Start_Date, End_Date, Salary, City, Description)
VALUES
('08', 'James', 'Cat', to_date('19960917','YYYYMMDD'), to_date('20020415','YYYYMMDD'), 1232.78, 'Vancouver', 'Tester');
Here for the Sequence that will manage Primary key (ID)
CREATE SEQUENCE "TEST"."EMPLOYEE_SEQ" MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOCACHE ORDER NOCYCLE ;
And here the code to execute the procedure
BEGIN
employeepackage.duplicateemployee(5);
END;
I really don't understand why it doesn't properly work for a single row when it's working to plicate all rows ? It there a limitation for cursors having less than 2 rows ?
Any help would be much appreciated ;)
Why do you need a cursor? You can do this with SQL directly:
INSERT INTO Employee(id, first_name, last_name,
start_date, end_date,
salary, city, description)
SELECT employee_seq.NEXTVAL, e.first_name, e.last_name,
e.start_date, e.end_date,
e.salary, e.city, e.description
FROM Employee e
WHERE e.id = p_EmployeeID;
Anyway, the actual problem is that your ID is a VARCHAR2(4), whereas you think it is a NUMBER. You actually do not have an employee with ID = 5, but you do have one with ID = '05'. So without changing anything, your procedure already works:
BEGIN
employeepackage.duplicateemployee('05');
END;
Of course, it would make sense to change the data type of ID.
Solution from Lukas if fine for my first and last table that will not need to call others PROCEDURE to duplicate multiple children, though for intermediate table I used :
PROCEDURE Duplicate_Company (p_IdCity IN City.IdCity%TYPE) AS
p_New_IdCompany Company.IdCompany%TYPE;
CURSOR c_DuplicateCompany IS
SELECT *
FROM Company c
WHERE c.IdCity = p_IdCity;
row_Company c_DuplicateCompany%ROWTYPE;
BEGIN
FOR c1 IN c_DuplicateCompany LOOP
p_New_IdCompany := company_seq.NEXTVAL;
INSERT INTO Company(IdCompany, IdCity, Name, CreationDate)
VALUES(p_New_IdCompany, c1.IdCity, c1.Name, c1.CreationDate);
-- Call the procedure to duplicate current employee
Duplicate_Employee(c1.IdCompany);
END LOOP;
END Duplicate_Company;
Is it a good approach ?

Resources