Is the use of cursor needed to achieve the following query? - mysql

Consider the database:
A Company has zero or more Branch companies
A Company has zero or more Emails
A Branch has zero or more Emails
And consider the following instance of that database:
1 Company with 2 Branches
The Company has 1 Email
Each branch has 2 Emails
(5 Emails in total)
If you prefer, check the graphical representation of that instance.
Query
I'd like to make a query (MySQL) that retrieves all e-mails related to a given company (5, in the example). I couldn't find a solution, so after a bit of googling I found out that there's a thing called cursor.
Question
Is the use of cursor needed to achieve the query above? Would it be a good solution? What would be your solution to the query above?
(tables are defined below)
My idea was to retrieve all branches for a given company (that query I could make), but from there I don't know how to iterate through the branches (result of the query) and get all the e-mails.
Tables definitions in MySQL
-- Database tables
CREATE TABLE `company` (
`c_id` INT(11) NOT NULL AUTO_INCREMENT,
`c_name` VARCHAR(45) NOT NULL,
PRIMARY KEY (`c_name`),
UNIQUE KEY `c_id` (`c_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `branch` (
`b_id` INT(11) NOT NULL AUTO_INCREMENT,
`c_id` INT(11) NOT NULL,
`b_name` VARCHAR(45) NOT NULL,
PRIMARY KEY (`b_name`),
UNIQUE KEY `b_id` (`b_id`),
KEY `c_id` (`c_id`),
CONSTRAINT `branch_ibfk_1` FOREIGN KEY (`c_id`)
REFERENCES `company` (`c_id`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
CREATE TABLE `email` (
`e_id` INT(11) NOT NULL AUTO_INCREMENT,
`e_addr` VARCHAR(45) NOT NULL,
PRIMARY KEY (`e_addr`),
UNIQUE KEY `e_id` (`e_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
CREATE TABLE `c_email` (
`c_id` INT(11) NOT NULL,
`e_id` INT(11) NOT NULL,
PRIMARY KEY (`c_id`,`e_id`),
KEY `e_id` (`e_id`),
CONSTRAINT `c_email_ibfk_1` FOREIGN KEY (`c_id`)
REFERENCES `company` (`c_id`)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `c_email_ibfk_2` FOREIGN KEY (`e_id`)
REFERENCES `email` (`e_id`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `b_email` (
`b_id` INT(11) NOT NULL,
`e_id` INT(11) NOT NULL,
PRIMARY KEY (`b_id`,`e_id`),
KEY `e_id` (`e_id`),
CONSTRAINT `b_email_ibfk_1` FOREIGN KEY (`b_id`)
REFERENCES `branch` (`b_id`)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `b_email_ibfk_2` FOREIGN KEY (`e_id`)
REFERENCES `email` (`e_id`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- Example of query
-- Retrieving all e-mails of a given branch
SELECT e_addr
FROM email AS _em
JOIN b_email AS _be ON _be.e_id = _em.e_id
JOIN branch AS _br ON _br.b_id = _be.b_id
WHERE b_name = #bra2;
-- How to retrieve all e-mails related to a given company
-- (e-mails from the company itself and also from all of its branches)?
-- ?

No, you don't need a cursor for this. You can do this with SQL -- much better than a cursor. It is something like:
select *
from ((select ce.c_id, e.email
from c_email ce join
email e
on e.e_id = ce.e_id
) union all
(select b.c_id, e.email
from branch b join
b_email be
on b.b_id = be.b_id join
email e
on be.e_id = e.e_id
)
) e
where ce.c_id = X;
EDIT:
You can add b_id into the second subquery but not the first. Perhaps you could do:
select *
from ((select ce.c_id, e.email, NULL as b_id
from c_email ce join
email e
on e.e_id = ce.e_id
) union all
(select b.c_id, e.email, b.b_id
from branch b join
b_email be
on b.b_id = be.b_id join
email e
on be.e_id = e.e_id
)
) e
where ce.c_id = X
order by c_id, b_id;

Related

How to delete data in two linked tables (many-to-many relationship) with one query?

There are tables films,actors and the table binding them films_actors.
CREATE code:
CREATE TABLE `actors` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(50) NOT NULL,
`surname` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=9
;
CREATE TABLE `films` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NOT NULL,
`release` SMALLINT(4) NOT NULL,
`format` VARCHAR(10) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=6
;
CREATE TABLE `films_actors` (
`id_film` INT(11) NOT NULL,
`id_actor` INT(11) NOT NULL,
INDEX `FK_films_actors_actors` (`id_actor`),
INDEX `FK_films_actors_films` (`id_film`),
CONSTRAINT `FK_films_actors_actors` FOREIGN KEY (`id_actor`) REFERENCES `actors` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `FK_films_actors_films` FOREIGN KEY (`id_film`) REFERENCES `films` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
If I delete data from the tables actors orfilms, then the data will automatically be deleted from the films_actors table, the question is whether one query can delete data from all three tables at once?
Here is the query that I tried to write, but without success.
delete
from films, actors
where actors.id in (
select films_actors.id_actor from films_actors
where films_actors.id_film = 5
) and films.id = films_actors.id_film
You could use an delete join and use a subquery in join for manage the IN clause
delete films.*, actors.*
from films
INNER JOIN (
select films_actors.id_actor, id_film
from films_actors
where films_actors.id_film = 5
) t ON films.id = t.id_film
INNER JOIN actors ON actors.id = t.id_actor
You should be able to do:
delete f, a, fa
from films f join
films_actors fa
on fa.id_film = f.id join
actors a
on fa.id_actor = a.id
where f.id = 5;
This seems dangerous, because actors could be in other films. I assume you only really want to delete from f and fa.

Create view with two reference to the same table

I have two tables
CREATE TABLE `persons` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`first_name` varchar(45) NOT NULL,
`last_name` varchar(45) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
CREATE TABLE `marriage` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`place` varchar(45) DEFAULT NULL,
`spouse1` int(11) NOT NULL,
`spouse2` int(11) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `sp1` FOREIGN KEY (`id`) REFERENCES `persons` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `sp2` FOREIGN KEY (`id`) REFERENCES `persons` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
Now I would like to create the view with place of marriage and full names of both spouse. How can I do it? I tried like this (obviously not correctly):
CREATE
ALGORITHM = UNDEFINED
DEFINER = `root`#`localhost`
SQL SECURITY DEFINER
VIEW `mar` AS
select
`marriage`.`place` AS `place`,
`persons`.`first_name` AS `first_name_sp1`,
`persons`.`first_name` AS `first_name_sp2`
from
(`persons`
join `marriage`)
where
((`marriage`.`spouse1` = `persons`.`id`)
and (`marriage`.`spouse2` = `persons`.`id`))
The select that you want needs to mention persons twice:
select m.place, p1.first_name as first_name_sp1,
p2.first_name as first_name_sp2
from marriage m join
persons p1
on m.spouse1 = p1.id join
persons p2
on m.spouse2 = p2.id;
You can put this in a view just by putting create view mar as before it.
And note the use of table aliases to distinguish between the two tables. This is a case where table aliases are required. However, they often make a query easier to write and to read.
JOIN to Persons Twice, using aliases, and I would suggest replacing the WHERE joins with an ANSI JOIN:
select
m.place AS place,
p1.first_name` AS first_name_sp1,
p2.first_name AS first_name_sp2
from
marriage m
INNER JOIN persons p1
ON m.spouse1 = p1.id
INNER JOIN persons p2
ON m.spouse2 = p2.id

Understanding MySql queries

Trying to teach my self a bit of mysql and php and decided to do that by working on actual project with help oh "how to do everything with MySQL and PHP book".
first problem i have is with understanding joint table queries.
here are my tables:
CREATE TABLE `clients` (
`id` SMALLINT(6) NOT NULL AUTO_INCREMENT,
`client` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `KlientID` (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=8;
CREATE TABLE `facilities` (
`id` SMALLINT(6) NOT NULL AUTO_INCREMENT,
`facility` VARCHAR(45) NOT NULL,
`fk_client` SMALLINT(6) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `fk_idklijent_idx` (`fk_client`),
CONSTRAINT `FK_client_id` FOREIGN KEY (`fk_client`) REFERENCES `clients` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=35;
CREATE TABLE `models` (
`id` SMALLINT(6) NOT NULL AUTO_INCREMENT,
`model` VARCHAR(50) NOT NULL,
`fk_manufacturer` SMALLINT(6) NOT NULL,
PRIMARY KEY (`id`),
INDEX `ModelID` (`id`),
INDEX `fk_proizvodjacID_idx` (`fk_manufacturer`),
CONSTRAINT `FK_manuf_id` FOREIGN KEY (`fk_manufacturer`) REFERENCES `manufacturers` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=9;
CREATE TABLE `machines` (
`id` SMALLINT(6) NOT NULL AUTO_INCREMENT,
`serial` VARCHAR(50) NOT NULL,
`fk_model` SMALLINT(6) NOT NULL,
`InvBr` INT(11) NULL DEFAULT '0',
`fk_facilities` SMALLINT(6) NULL DEFAULT '0',
`sw` VARCHAR(255) NULL DEFAULT NULL,
`adaptation` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `FK_uredjaji_modeli` (`fk_model`),
INDEX `FK_uredjaji_poslovnice` (`fk_facilities`),
INDEX `Index 4` (`serial`),
CONSTRAINT `FK_facility_id` FOREIGN KEY (`fk_facilities`) REFERENCES `facilities` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `FK_models_id` FOREIGN KEY (`fk_model`) REFERENCES `models` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=93;
CREATE TABLE `technicians` (
`id` SMALLINT(6) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `ServiserID` (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=5;
CREATE TABLE `workorders` (
`id` SMALLINT(6) NOT NULL AUTO_INCREMENT,
`wo_nr` VARCHAR(50) NOT NULL,
`fk_machine_id` SMALLINT(6) NOT NULL,
`fk_technitian_id` SMALLINT(6) NOT NULL,
`counter` INT(11) NOT NULL DEFAULT '0',
`service_date` DATE NOT NULL,
`description` LONGTEXT NOT NULL,
`work_hours` INT(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
INDEX `FK_rn_serviseri` (`fk_technitian_id`),
INDEX `FK_machines_id_idx` (`fk_machine_id`),
CONSTRAINT `FK_machines_id` FOREIGN KEY (`fk_machine_id`) REFERENCES `machines` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT `FK_technitian_id` FOREIGN KEY (`fk_technitian_id`) REFERENCES `technicians` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1393;
using this query i get each row 8 times.
SELECT DATE_FORMAT (w.service_date, '%d.%m.%Y'), f.facility, m.model, mc.serial, w.description, t.name
FROM workorders AS w, facilities AS f, models AS m, machines AS mc, technicians AS t
WHERE f.id = mc.fk_facilities AND w.fk_machine_id = mc.id AND w.fk_technitian_id = t.id AND w.service_date > '2009-12-31'
ORDER BY w.service_date DESC;
can someone pls point me to what i'm doing wrong. i only need rows from workorders table. other tables are here only to show real data not only id's - bad, not true :(
thx
edit 1:
i need a list of workorders. to explain my question little more here is how the result should look like:
[date][name of the facility the machine (fk_machine_id) belongs to][model of the machine (fk_machine_id)][serial number of the machine (fk_machine_id)][description from workorder][technician name (fk_technician_id)]
edit2:
here is the model image
i think my problem is in fact that to get the model i need to check with machines table first. Same thing with facility.
got it!
the problem was in one missing AND.
final SELECT looks like this:
SELECT DATE_FORMAT (w.service_date, '%d.%m.%Y') AS service_date, w.wo_nr, f.facility, m.model, mc.serial, FORMAT (w.counter, 0) AS Counter, w.description, t.name AS technician
FROM workorders AS w, technicians AS t, machines AS mc, models AS m, facilities AS f
WHERE mc.fk_facilities = f.id
AND w.fk_machine_id = mc.id
AND mc.fk_model = m.id
AND w.fk_technitian_id = t.id
AND w.service_date > '2009-12-31'
ORDER BY w.service_date DESC;
thx all. moving on to the next problem :)
to get only rows from workorders table use this query
SELECT w.*
FROM workorders AS w, facilities AS f, models AS m, machines AS mc, technicians AS t
WHERE f.id = mc.fk_facilities AND w.fk_machine_id = mc.id AND w.fk_technitian_id = t.id AND w.service_date > '2009-12-31'
ORDER BY w.service_date DESC;
You say you only want data from the workorders table. Then you don't need all the other joins.
SELECT * FROM workorders WHERE service_date > '2009-12-31'
Unless you need the columns in their tables as well.
Not too sure exactly what you require though.
Only put the columns you want returned in your results set in the SELECT section of your query. You can still include columns from other tables in your joins, they just won't be displayed. Also if you are getting multiple rows then either your data contains duplicates in which case you should look at your keys and constraints or you are missing one or more joins.
Would this work for you?
SELECT DISTINCT DATE_FORMAT (w.service_date, '%d.%m.%Y') as service_date,
f.facility, m.model, mc.serial, w.description, t.name
FROM workorders AS w, facilities AS f, models AS m, machines AS mc, technicians AS t
WHERE f.id = mc.fk_facilities
AND w.fk_machine_id = mc.id
AND w.fk_technitian_id = t.id
AND w.service_date > '2009-12-31'
ORDER BY w.service_date DESC;

Joining 3+ tables using SQL displaying too many results

im trying to create a query to join these tables together using this method below. However it is repeating results and they are not linking up correctly. as in the same rating comment would be on about 4/5 different results etc. its producing 18ish results when im expecting 3. would anyone be willing to help me with this problem?
SELECT a.Company_name,
f.Job_ID,
f.Job_Name,
b.User_Name,
c.Comments,
c.Reliability,
c.Rating
FROM company a,
Users b,
Ratings c,
UserCompJobRating d,
Company_Job e,
Jobs f
WHERE d.Comp_job_ID = e.Comp_Job_ID
AND b.users_ID = d.users_ID
AND c.Rating_ID = d.Rating_ID;
Many Thanks,
Andrew
ok i tried this and it is saying e.Users_ID is an unknown column in 'on clause'
SELECT a.Company_name,
b.Job_ID,
b.Job_Name,
c.User_Name,
d.Comments,
d.Reliability,
d.Rating
FROM Company a, UserCompJobRating e, Jobs b
INNER JOIN Users c
ON c.Users_ID = e.Users_ID
inner join Company_Job f
on e.Comp_Job_ID = f.Comp_Job_ID
inner join Ratings d
on d.Rating_ID = e.Rating_ID;
I'm assuming im close, however way off at the same time?
Ill try to give you some more information:
UserCompJobRating has a primary key UCJR_ID and 3 foreign keys of Comp_Job_ID, Users_ID and Rating_ID
Company_Job table as a primary key Comp_Job_ID, and 2 foreign keys Job_ID, Company_ID
Ratings Table has just the Rating_ID as a primary key and the rest just to do with the rating information
Users Table has a Users_ID as a primary key and basic user information address etc etc
Jobs Table has a Job_ID primary key and basic information about the job, such as name, price, etc.
Company Table has Company_ID as a primary key and the basic company information, similar to the Users table.
Here are the definations:
CREATE TABLE `company` (
`Company_ID` int(11) NOT NULL AUTO_INCREMENT,
`Company_Name` varchar(45) NOT NULL,
`CAddress` varchar(45) NOT NULL,
`CTown` varchar(45) NOT NULL,
`CPostcode` varchar(12) NOT NULL,
`CTelephone` varchar(45) NOT NULL,
PRIMARY KEY (`Company_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
CREATE TABLE `company_job` (
`Comp_Job_ID` int(11) NOT NULL AUTO_INCREMENT,
`Company_ID` int(11) NOT NULL,
`Job_ID` int(11) NOT NULL,
PRIMARY KEY (`Comp_Job_ID`),
KEY `Company_ID_idx` (`Company_ID`),
KEY `Job_ID_idx` (`Job_ID`),
CONSTRAINT `Company_ID` FOREIGN KEY (`Company_ID`) REFERENCES `company` (`Company_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Job_ID` FOREIGN KEY (`Job_ID`) REFERENCES `jobs` (`Job_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
CREATE TABLE `jobs` (
`Job_ID` int(11) NOT NULL AUTO_INCREMENT,
`Job_Name` varchar(45) NOT NULL,
`Job_Cost` varchar(45) DEFAULT NULL,
`Job_Avg_Time` varchar(45) DEFAULT NULL,
`Job_Avg_Cost` varchar(45) DEFAULT NULL,
`Job_Description` varchar(45) NOT NULL,
`Company_ID` int(11) NOT NULL,
PRIMARY KEY (`Job_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `ratings` (
`Rating_ID` int(11) NOT NULL AUTO_INCREMENT,
`Comments` varchar(200) DEFAULT NULL,
`Cost` varchar(45) DEFAULT NULL,
`Reliability` varchar(45) DEFAULT NULL,
`Rating` int(11) DEFAULT NULL,
PRIMARY KEY (`Rating_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `usercompjobrating` (
`UCJR_ID` int(11) NOT NULL AUTO_INCREMENT,
`Comp_Job_ID` int(11) DEFAULT NULL,
`Rating_ID` int(11) DEFAULT NULL,
`Users_ID` int(11) DEFAULT NULL,
PRIMARY KEY (`UCJR_ID`),
KEY `Comp_Job_ID_idx` (`Comp_Job_ID`),
KEY `Rating_ID_idx` (`Rating_ID`),
KEY `User_ID_idx` (`Users_ID`),
CONSTRAINT `Comp_Job_ID` FOREIGN KEY (`Comp_Job_ID`) REFERENCES `company_job` (`Comp_Job_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Rating_ID` FOREIGN KEY (`Rating_ID`) REFERENCES `ratings` (`Rating_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Users_ID` FOREIGN KEY (`Users_ID`) REFERENCES `users` (`Users_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `users` (
`Users_id` int(11) NOT NULL AUTO_INCREMENT,
`User_Name` varchar(45) NOT NULL,
`UAddress` varchar(45) NOT NULL,
`UTown` varchar(45) NOT NULL,
`UPostcode` varchar(45) NOT NULL,
`UTelephone` varchar(45) NOT NULL,
`UDOB` varchar(45) NOT NULL,
PRIMARY KEY (`Users_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
The query needs to look something like this i.e. use this form
SELECT a.Company_name,
f.Job_ID,
f.Job_Name,
b.User_Name,
c.Comments,
c.Reliability,
c.Rating
FROM company a
INNER JOIN Users b
ON a.???? = b.???
Since I dont have your table definitions I cant help you with the JOIN conditions. Show us the tables definition and we would be able to help.
UPDATE:
So based on your table structures you will be looking for something like this:
SELECT *
FROM company cmp
INNER JOIN company_job cmpjb
ON cmp.Company_ID = cmpjb.Company_ID
INNER JOIN jobs jb
ON cmpjb.Job_ID = jb.Job_ID
INNER JOIN usercompjobrating ucmpjbr
ON ucmpjbr.Comp_Job_ID = ucmpjbr.Comp_Job_ID
INNER JOIN users usr
ON usr.Users_id = ucmpjbr.Users_ID
INNER JOIN ratings rat
ON rat.Rating_ID = ucmpjbr.Rating_ID
Note you cannot use the folder table in this join as there are no primary/foreign key relationships to any of the other tables from the folder table.
I would suggest that you carefully dissect this query and let me know if you need to understand the details.
One thing to clarify, what is company_id in table jobs?
select ... (necessary fields to select)
from company c
join company_job cj using (company_id)
join jobs j using (job_id)
join usercompjobrating ucjr using (comp_job_id)
join ratings using (rating_Id)
join users using (users_id)

MySQL link table with extra fields creates cartesian product

I'm trying to build an app that besides recording number of sales also maintains the history between a supervisor and his/her team.
CREATE TABLE `emp` (
`id` int(11) NOT NULL,
`nombre` varchar(45) NOT NULL,
`apellido` varchar(45) NOT NULL,
`tl_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `tlFK_idx` (`tl_id`),
CONSTRAINT `tlFK` FOREIGN KEY (`tl_id`) REFERENCES `emp` (`id`)
CREATE TABLE `super` (
`id` int(11) NOT NULL,
`nombre` varchar(45) NOT NULL,
`apellido` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `emp_super` (
`emp_id` int(11) NOT NULL,
`super_id` int(11) NOT NULL,
`fecha` date NOT NULL,
PRIMARY KEY (`emp_id`,`super_id`,`fecha`),
KEY `empFK_idx` (`emp_id`),
KEY `superFK_idx` (`super_id`),
CONSTRAINT `empsuperFK` FOREIGN KEY (`emp_id`) REFERENCES `emp` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `super_empFK` FOREIGN KEY (`super_id`) REFERENCES `super` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
)
As you can see, the table emp_super is the link table with the exception of having a date field.
emp_id super_id fecha
101863 101404 2012-10-15
101863 101503 2012-10-01
102403 101404 2012-10-15
102403 101503 2012-10-01
103052 101404 2012-10-15
103052 101503 2012-10-01
103718 101404 2012-10-15
103718 101503 2012-10-01
The key is to keep a record of when a supervisor was assigned to a group, so that when there is any change, the new supervisor would not inherit his group's performance under the previous leader.
I've been working on a query to extract the sales made by a particular group but I immediately noticed that even though I think I'm making all the right connections, I receive a Cartesian product.
Here's the sales table:
CREATE TABLE `sales` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sale_date` date NOT NULL,
`product_id` int(11) NOT NULL,
`emp_id` int(11) NOT NULL,
`qty` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `empFK_idx` (`emp_id`),
KEY `campaignFK_idx` (`product_id`),
CONSTRAINT `empFK` FOREIGN KEY (`emp_id`) REFERENCES `emp_super` (`emp_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `productFK` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
)
Normally, when dealing with dates, I try and limit the dates to the main table my data is coming from but in this case I need to also take into account the dates for the employee-supervisor relationship.
My query so far is this:
SELECT s.sale_date,su.id,concat_ws(' ',su.nombre,su.apellido), p.name,e.id,concat_ws(' ',e.nombre,e.apellido), s.qty
from tracker.emp e, tracker.products p, tracker.sales s,tracker.super su, tracker.emp_super es
where e.id = es.emp_id
and su.id = es.super_id
and s.product_id = p.id
and e.id = s.emp_id
and s.sale_date between '2012-10-01' and '2012-10-15'
and es.fecha between '2012-10-01' and '2012-10-15'
order by su.id,p.name,e.id;
If I reduce the dates to the 14, then I receive the correct result because the other supervisor did not join until the 15. Has anyone ever encountered this business requirement: to maintain a record of leadership so that a new leader does not inherit his predecessors achievements or mistakes?
Thank you for any suggestions you might have.
You need to take account of when the supervisory role ended.
This will give you that but I suspect that it will not be very efficient.
SELECT e1.emp_id
,e1.super_id
,e1.fecha
,MIN(DATEADD(DAY, -1, e2.fecha)) AS end
FROM emp_super e1
INNER JOIN
emp_super e2 ON e1.emp_id=e2.emp_id
AND
e1.fecha<e2.fecha
GROUP BY e1.emp_id
,e1.super_id
,e1.fecha
Perhaps an end column on the link table updated by a TRIGGER would be better?