database: how to create the update cascade tables and query data? - mysql

I want to create a database have two tables. I want to create a update cascade relationship between two tables. If the SNAME was changed in EMPLOYEE, then WORKREPORT will change his SNAME too.
EMPLOYEE:
SNO SNAME SPASSWORD SEX BDATE HEIGHT BTITLE
2014 boss 12345 male 1987-06-02 180 Manager
2015 Tom 1234567 male 1987-06-05 180 Employee
WORKREPORT
SNO SNAME SDATA SCHECKLIST SIMAGE
2014 boss 1987-06-02 abc afafafaf
2015 Tom 1987-06-05 affafa afafafaf
My code works very well. My problems is that : I don't know how to only query the employee's information(rather than manager) from the "WORKREPORT", suppose there are many employees. What should I do? Am I right about about the designing "WORKREPORT"?
This is my code:
CREATE database if not exists cm360_cm360_1;
use cm360_cm360_1;
CREATE TABLE IF NOT EXISTS EMPLOYEE(SNO VARCHAR(7) NOT NULL, SNAME VARCHAR(8) NOT NULL, SPASSWORD VARCHAR(11) NOT NULL,SEX VARCHAR(8) NOT NULL, BDATE DATETIME NOT NULL, HEIGHT DEC(5,2) DEFAULT 000.00,BTitle VARCHAR(15) NOT NULL, PRIMARY KEY(SNO), UNIQUE KEY (SNAME))ENGINE=InnoDB ;
SET SQL_SAFE_UPDATES=0;
INSERT INTO EMPLOYEE VALUES (2014,'boss','12345','male','2014-6-10 11:00:00',160.00,'Manager');
INSERT INTO EMPLOYEE VALUES (2015,'Tom','1234567','male','2014-6-10 12:00:00',160.00,'Employee');
SELECT * FROM EMPLOYEE;
CREATE TABLE IF NOT EXISTS WORKREPORT(SNO VARCHAR(7) NOT NULL, SNAME VARCHAR(8) NOT NULL,SDATA DATETIME , SCHECKLIST VARCHAR(150),SIMAGE VARCHAR(20),FOREIGN KEY (SNO) REFERENCES EMPLOYEE (SNO) ON UPDATE CASCADE,FOREIGN KEY(SNAME) REFERENCES EMPLOYEE (SNAME) ON UPDATE CASCADE ) ENGINE=InnoDB;
INSERT INTO WORKREPORT VALUES (2014,'boss',' 2014-6-10 14:38:59','abc','afdsfdfds');
INSERT INTO WORKREPORT VALUES (2015,'Tom',' 2014-6-10 15:38:59','abc','afdsfdfds');
SELECT * FROM WORKREPORT order by SDATA ASC;
UPDATE WORKREPORT SET SCHECKLIST='elevator;floor' WHERE SNAME='hanlu2';
delete from workreport WHERE SIMAGE='N/A' AND SNAME='enlan';

If you want to get Employee WORKREPORT information, query below should work..
SELECT WORKREPORT.*
FROM WORKREPORT, EMPLOYEE
WHERE EMPLOYEE.SNO = WORKREPORT.SNO
AND EMPLOYEE.BTITLE = "Employee"

If you just want to get all employee information, you can JOIN the two tables on SNO and/or SNAME since you have a FK relationship on those column and filter by the condition that BTITLE shouldn't be MANAGER
select e.*
from employee e
join workreport w on e.SNO = w.SNO
and e.SNAME = w.SNAME
and e.BTITLE <> 'Manager'

Related

Altering a Table to Add a Column thats Value is set using a UPDATE JOIN Query

Im trying to create a Column thats Value is defined through anUPDATE JOIN SET statement. The exact question that im trying to answer actually is
"Add to a relational table EMPLOYEE information about the total number of orders handled by each employee. Note, that if an employee handled no orders then for such employee the total number of orders must be set to zero. Enforce the appropriate consistency constraints on a relational table EMPLOYEE. "
ALTER TABLE EMPLOYEE
ADD TOTALNUMBER VARCHAR(40) NOT NULL;
UPDATE EMPLOYEE E JOIN ORDERS O ON(E.EMPLOYEE_ID = O.EMPLOYEE_ID)
SET E.TOTALNUMBER = E.EMPLOYEE_ID + O.ORDER_ID;
UPDATE EMPLOYEE
SET TOTALNUMBER = 0
WHERE TOTALNUMBER IS NULL;
tables being used
CREATE TABLE EMPLOYEE
(
EMPLOYEE_ID DECIMAL(9) NOT NULL,
LASTNAME VARCHAR(20) NOT NULL,
FIRSTNAME VARCHAR(10) NOT NULL,
TITLE VARCHAR(30),
TITLE_OF_COURTESY VARCHAR(25),
BIRTHDATE DATE,
HIREDATE DATE,
ADDRESS VARCHAR(60),
CITY VARCHAR(15),
REGION VARCHAR(15),
POSTAL_CODE VARCHAR(10),
COUNTRY VARCHAR(15),
HOME_PHONE VARCHAR(24),
EXTENSION VARCHAR(4),
PHOTO VARCHAR(255),
NOTES VARCHAR(2000),
REPORTS_TO DECIMAL(9),
CONSTRAINT PK_EMPLOYEE PRIMARY KEY (EMPLOYEE_ID)
);
CREATE TABLE ORDERS
(
ORDER_ID DECIMAL(9) NOT NULL,
CUSTOMER_CODE VARCHAR(5) NOT NULL,
EMPLOYEE_ID DECIMAL(9) NOT NULL,
ORDER_DATE DATE NOT NULL,
REQUIRED_DATE DATE,
SHIPPED_DATE DATE,
SHIP_VIA VARCHAR(40),
FREIGHT DECIMAL(10,2) DEFAULT 0,
SHIP_NAME VARCHAR(40),
SHIP_ADDRESS VARCHAR(60),
SHIP_CITY VARCHAR(15),
SHIP_REGION VARCHAR(15),
SHIP_POSTAL_CODE VARCHAR(10),
SHIP_COUNTRY VARCHAR(15),
CONSTRAINT PK_ORDERS PRIMARY KEY (ORDER_ID),
CONSTRAINT FK_CUSTOMER_CODE FOREIGN KEY (CUSTOMER_CODE) REFERENCES CUSTOMER(CUSTOMER_CODE),
CONSTRAINT FK_EMPLOYEE_ID FOREIGN KEY (EMPLOYEE_ID) REFERENCES EMPLOYEE(EMPLOYEE_ID),
CONSTRAINT FK_SHIP_VIA FOREIGN KEY (SHIP_VIA) REFERENCES SHIPPER(COMPANY_NAME)
);
Im unsure of what the exact result should be but i recieve a total of 9 rows with values ranging between 252 to 296. It doesnt seem to odd that an employee would deal with this many Orders but it seems to be too small of a list.
I don't recommend your current approach, and the best way to determine the number of orders per employees is to just aggregate and join, without storing this number in the actual employee table. That being said, if you want to proceed this way, then consider using this update query:
UPDATE EMPLOYEE e
LEFT JOIN
(
SELECT EMPLOYEE_ID, COUNT(*) AS num_orders
FROM ORDERS
GROUP BY EMPLOYEE_ID
) o
ON e.EMPLOYEE_ID = o.EMPLOYEE_ID
SET TOTALNUMBER = COALESCE(o.num_orders, 0);
Or, you could use:
SET TOTALNUMBER = o.num_orders;
and then use your second update to zero-out the employee totals which had no orders at all:
UPDATE EMPLOYEE
SET TOTALNUMBER = 0
WHERE TOTALNUMBER IS NULL;
But note that this would require that the TOTALNUMBER columns is not nullable. So you would need to remove the NOT NULL constraint.

How shall I modify my trigger so that I can get the total_employees according to their departments?

tables are given below.
CREATE TABLE `departments` (
department_id INT(2) NOT NULL AUTO_INCREMENT,
department_name VARCHAR(30) NOT NULL,
total_employees INT(4),
PRIMARY KEY (department_id),
UNIQUE (department_name));
CREATE TABLE `employees` (
employee_id INT(4) NOT NULL AUTO_INCREMENT,
employee_email VARCHAR(30) NOT NULL,
employee_first_name VARCHAR(30) NOT NULL,
employee_last_name VARCHAR(30) NOT NULL,
department_name VARCHAR(30) NOT NULL,
PRIMARY KEY (employee_id),
UNIQUE (employee_email),
FOREIGN KEY (department_name)
REFERENCES departments (department_name)
ON DELETE CASCADE);
this is the trigger, I want it to be showing the sum of total employees in each department.
delimiter $$
create trigger department_wise_total_employee_counting
after insert on employees
for each row begin update departments set total_employees=total_employees+1
where department_id=department_id; end$$ delimiter ;
INSERT INTO `departments`
VALUES
(1,'HRM',0),(2,'Accounting',0);
INSERT INTO `employees`
VALUES
(1,'bh#gmail.com','A','B','HRM'),
(2,'ak#gmail.com','C','D','HRM'),
(3,'mr#gmail.com','E','F','HRM'),
(4,'pr#gmail.com','G','H','Accounting');
On running the following query :
select * from departments;
I'm getting this output, which just gives the total employee count rather than the total for each department.
I am trying to get total_employees=3 for HRM and total_employees=1 for Accounting.
Would appreciate any sort of suggestions.
As was pointed out by #P.Salmon, in general you shouldn't store data you can easily calculate. For this application, a VIEW (as suggested by #TamilSelvanC) is a good solution. For example:
CREATE VIEW departments_view AS
SELECT d.department_id, d.department_name, COUNT(e.employee_id) AS total_employees
FROM departments d
LEFT JOIN employees e ON e.department_name = d.department_name
GROUP BY d.department_id;
SELECT * FROM departments_view
Output:
department_id department_name total_employees
1 HRM 3
2 Accounting 1
3 Engineering 0
Demo on dbfiddle

MySQL - Row Deletion on one table does not update relationship at other table

I have 2 tables, one for the Employees and another for the Departments. A department can have multiple/different employees but one employee may only work in one Department. Their relationship is one to many.
Table Creations:
CREATE TABLE IF NOT EXISTS department(
id INT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE,
street VARCHAR(255) NOT NULL,
employees_count INT(20) DEFAULT '0')
ENGINE=INNODB;
CREATE TABLE IF NOT EXISTS employee(
id INT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
born INT(20) NOT NULL,
country VARCHAR(255) NOT NULL,
department_name VARCHAR(255) NOT NULL,
FOREIGN KEY (department_name) REFERENCES department(name)
ON UPDATE CASCADE ON DELETE CASCADE)
ENGINE=INNODB;
Table Insertions:
INSERT INTO department(name,street) VALUES ('Alexandroupoli', 'Leoforos Dimokratias21');
INSERT INTO department(name,street) VALUES ('Athens','Basilisis Sofias 111');
INSERT INTO department(name,street) VALUES ('Patras','Smurnis 34');
INSERT INTO department(name,street) VALUES ('Kalamata','Leoforos Fountas 241');
INSERT INTO department(name,street) VALUES ('Heraklion','Leoforos Enetwn 132');
INSERT INTO department(name,street) VALUES ('Thessaloniki','Karolou 45');
INSERT INTO department(name,street) VALUES ('Xanthi','Agia Barbasa 68');
INSERT INTO department(name,street) VALUES ('Larisa','Hroon Polutexneiou 12');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Vaggelis','Michos','vagg7#gmail.com','1995','Greece','Athens');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('James','Gunn','james8#gmail.com','1970','USA','Athens');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('George','McMahon','george95#gmail.com','1978','Usa','Patras');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('John','Jones','john13#gmail.com','1992','England','Patras');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Marinos','Kuriakopoulos','marin_kur#gmail.com','1986','Greece','Alexandroupoli');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Dimitris','Nikolaou','dimitis8#yahoo.gr','1984','Greece','Larisa');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Soufiane','El Kaddouri','sofiane#yahoo.com','1974','France','Xanthi');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Maria','Apostolou','mariamaria1#gmail.com','1997','Greece','Larisa');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Ioannis','Marinou','ioannis_ap#yahoo.gr','1982','Greece','Kalamata');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Thanasis','Athanasiou','thanos89#gmail.com','1989','Cyprus','Heraklion');
UPDATE department SET employees_count = (SELECT COUNT(*) FROM employee WHERE department.name = employee.department_name);
Upon creating the 2 tables and creating a foreign key constraint between them, when I delete a Department from the department table, every assosiated employee get deleted too, just as I need.
BUT, when I delete an employee from the employee table, the employees_count row in department does not change. For example, if I have 2 employees with a department_name = Athens, then upon deleting one of them, when I go to departments table, the employees_count remains equal to 2 instead of 1.
Same thing happens upon updating the department_name in employees table. If for one employee, I update his department_name from "Athens" to lets say "Patras", the department table remains unchanged.
So I was thinking, after I delete an employee, maybe also execute this command
UPDATE department SET employees_count = (SELECT COUNT(*) FROM employee WHERE department.name = employee.department_name);
and that would certainly solve my issue.
BUT, is there a way for the employees_count column in department table to be AUTOMATICALLY assinged to the number of employees that work there instead of just being an integer field?
Is there a more practical way to solve this issue, instead of just adding the UPDATE command after each Deletion I make?
I'd say you don't need to store the department count in the table as a separate attribute; it's a value you can always find out through a query.
Also, deleting records can be very absolute. This is by no means best practice but I prefer to mark records as deleted (maybe with a time stamp). This is information, meta data I guess, that might be of interest. In this way all the employee information is retained. Food for thought.
Hope that was helpful.

MySQL UPDATE value in SQLfiddle

I've just started on SQL and so far I've made this and it works
CREATE TABLE employees(employee_ID int NOT NULL, name varchar(20) NOT NULL UNIQUE,
PRIMARY KEY (employee_ID)
);
INSERT INTO employees VALUES(1, 'Adam Jones');
INSERT INTO employees VALUES(2, 'Amy Smith');
INSERT INTO employees VALUES(3, 'Anthony Wright');
CREATE TABLE department(department_ID varchar(20) NOT NULL,
department_name varchar(20) NOT NULL, head_of_dep varchar(20),
num_of_employees_in_dep int
);
INSERT INTO department VALUES('Bad At SQL Ltd', 'Need Help HQ', 'No One Yet', 3);
But I cant understand why this wont work
UPDATE department SET head_of_dep = name FROM employees WHERE employee_ID = 1
What am I doing wrong?
Using SQLfiddle and MySQL 5.5.32
You need to rewrite it to
UPDATE department SET head_of_dep = (SELECT name FROM employees WHERE employee_ID = 1)
because you actually have to SELECT the value

Oracle table with only current records; reduce duplicates using max(date)

I need to create a new table in oracle with only the most current date for each record (step 1), and calculate days between (step 2).
Your suggestions are greatly appreciated:)))
Step 1: First I need to find the max (Mod_date) for each record from table USERS.
TABLE: USERS
Name................Mod_Date
Jason Martin....... 25-JUL-89
Al Mathews......... 21-MAR-89
James Smith........ 12-DEC-88
Robert Black....... 15-JAN-84
Jason Martin....... 25-JUL-99
Al Mathews......... 21-MAR-96
James Smith........ 12-DEC-98
Robert Black....... 15-JAN-94
*TABLE_DESIRED_RESULTS_step1
Name............... Max(Mod_Date)
Jason Martin....... 25-JUL-99
Al Mathews......... 21-MAR-96
James Smith........12-DEC-98
Robert Black.......15-JAN-94
Step 2: Calculate “Number of Days Between Regist_Date and Mod_Date” & add it to the table.
TABLE: REGISTRATION
Name................Regist_Date
Jason Martin.........20-JUL-99
Al Mathews...........23-MAR-96
Robert Black.........20-JAN-94
*TABLE_DESIRED_RESULTS_step2
Name...............Max(Mod_Date).....Number of Days Between Regist_Date and Mod_Date
Jason Martin...... 25-JUL-99..........5
Al Mathews........ 21-MAR-96.........-2
James Smith....... 12-DEC-98..........null
Robert Black...... 15-JAN-94..........-5
*Please note, this data is made up and I already have existing unions and joins to which I have to add this logic. Thanks and have a nice day!
here is my updated answer with a sample.
The important thing is that your date column have the DATE type.
Here is the tables and data following your specification.
CREATE TABLE USERS
(
ID_USER NUMBER(6) NOT NULL,
NAME VARCHAR2(64) NOT NULL,
MOD_DATE DATE NOT NULL,
CONSTRAINT PK_user PRIMARY KEY (ID_USER)
) ;
INSERT INTO USERS VALUES (1,'Jason Martin',TO_DATE('25-07-1989','DD-MM-YYYY'));
INSERT INTO USERS VALUES (2,'Al Mathews',TO_DATE('21-03-1989','DD-MM-YYYY'));
INSERT INTO USERS VALUES (3,'James Smith',TO_DATE('12-12-1988','DD-MM-YYYY'));
INSERT INTO USERS VALUES (4,'Robert Black',TO_DATE('15-01-1984','DD-MM-YYYY'));
INSERT INTO USERS VALUES (5,'Jason Martin',TO_DATE('25-07-1999','DD-MM-YYYY'));
INSERT INTO USERS VALUES (6,'Al Mathews',TO_DATE('21-03-1996','DD-MM-YYYY'));
INSERT INTO USERS VALUES (7,'James Smith',TO_DATE('12-12-1998','DD-MM-YYYY'));
INSERT INTO USERS VALUES (8,'Robert Black',TO_DATE('15-01-1994','DD-MM-YYYY'));
CREATE TABLE REGISTRATION
(
ID_REG NUMBER(6) NOT NULL,
NAME VARCHAR2(64) NOT NULL,
REGIST_DATE DATE NOT NULL,
CONSTRAINT PK_reg PRIMARY KEY (ID_REG)
) ;
INSERT INTO REGISTRATION VALUES (1,'Jason Martin',TO_DATE('20-07-1999','DD-MM-YYYY'));
INSERT INTO REGISTRATION VALUES (2,'Al Mathews',TO_DATE('23-03-1996','DD-MM-YYYY'));
INSERT INTO REGISTRATION VALUES (3,'Robert Black',TO_DATE('20-01-1994','DD-MM-YYYY'));
First step
CREATE TABLE TABLE_DESIRED_RESULTS_step1
AS (
SELECT
u.NAME
, max(u.MOD_DATE) as "maxi"
FROM USERS u
GROUP BY u.NAME);
second step
CREATE TABLE TABLE_DESIRED_RESULTS_step2
AS (
SELECT
t.NAME
,t."maxi"
, (t."maxi" - r.REGIST_DATE ) as "Nbdays bw RegD and Mod_D"
FROM TABLE_DESIRED_RESULTS_step1 t LEFT OUTER JOIN REGISTRATION r
ON t.NAME = r.NAME);
The trick here is that LEFT OUTER JOIN allows null value if there is no match with the join.
But there is a database design concern for me.
If you have 2 users with the exact same name , you will merge 2 persons in one.
Here a solution using IDs and doing the join on the IDs.
CREATE TABLE USERS
(
ID_USER NUMBER(6) NOT NULL,
NAME VARCHAR2(64) NOT NULL,
CONSTRAINT PK_user PRIMARY KEY (ID_USER)
) ;
CREATE TABLE MOD_USERS
(
ID_MOD NUMBER(6) NOT NULL,
ID_USER NUMBER(6) NOT NULL,
CONSTRAINT PK_usermod PRIMARY KEY (ID_MOD)
) ;
ALTER TABLE MOD_USERS ADD (
CONSTRAINT FK_user_mod
FOREIGN KEY (ID_USER)
REFERENCES USERS (ID_USER));
CREATE TABLE REGISTRATION
(
ID_REG NUMBER(6) NOT NULL,
ID_USER VARCHAR2(64) NOT NULL,
REGIST_DATE DATE NOT NULL,
CONSTRAINT PK_reg PRIMARY KEY (ID_REG)
) ;
ALTER TABLE REGISTRATION ADD (
CONSTRAINT FK_user_reg
FOREIGN KEY (ID_USER)
REFERENCES USERS (ID_USER))
;
First step
CREATE TABLE TABLE_DESIRED_RESULTS_step1
AS (
SELECT
m.ID_USER , u.NAME
, max(u.MOD_DATE) as "maxi"
FROM USERS u INNER JOIN MOD_USERS m
ON u.ID_USER = m.ID_USER
GROUP BY m.ID_USER , u.NAME);
second step
CREATE TABLE TABLE_DESIRED_RESULTS_step2
AS (
SELECT
t.ID_USER , t.NAME
,t."maxi"
, (t."maxi" - r.REGIST_DATE ) as "Nbdays bw RegD and Mod_D"
FROM TABLE_DESIRED_RESULTS_step1 t LEFT OUTER JOIN REGISTRATION r
ON t.ID_USER = r.ID_USER);