Your sql query is wrong:
- Assume there is a student s1 who has passed one exam
after '2000-01-01' and none before.
Your query results in {s1} - {} = {s1}. This will be a false positive.
- Assume there is a student s1 that passed three exams
after '2000-01-01' and one exam before.
Your query results in {s1} - {s1} = {}. This will be a false negative.
I'm having a bit of trouble reading your algebra expressions, but the first one looks ok. It should not matter that you do the selection (topic = "motorcycle") after the join instead of joining on the selection.
The second one can't be right. Assume there's a newspaper that published both an article on motorcycle and an article on something else. Your expression will pick the article on something else and therefore return that newspaper (incorrectly).
I think you're on the right track, but I'm not seeing a provision for restricting the results to employees who are actually working on two projects and the rename notation is confusing to me. You'll probably want to leverage a theta-join on a self join to accomplish this.
To start out, I would rename the relevant attributes in the work table in preparation for a self-join:
ρsin/emp_sin,project_number1/project_number works_on
Then project just those attributes for simplicity's sake:
πsin,project_number1 ( ρsin/emp_sin,project_number1/project_number works_on )
For visualization purposes, the equivalent SQL here would be something along the lines of:
SELECT emp_sin
AS sin,
project_number
AS project_number1
FROM works_on;
I'd then prepare for the self join by creating another relationship, renaming the project_number
differently:
πsin,project_number2 ( ρsin/emp_sin,project_number2/project_number works_on )
At this point, a theta-join can be applied, exploiting the maximum of 2 carnality as defined in the assumption. This theta-join creates a relationship with both project_numbers
by emp_sin
:
( πsin,project_number1 ( ρsin/emp_sin,project_number1/project_number works_on ) ) ⋈sin, project_number1 < project_number2 ( πsin,project_number2 ( ρsin/emp_sin,project_number2/project_number works_on ) )
In effect, this is similar to SQL as follows:
SELECT *
FROM ( SELECT emp_sin
AS sin,
project_number
AS project_number1
FROM works_on ) AS w1
INNER JOIN (
SELECT emp_sin
AS sin,
project_number
AS project_number2
FROM works_on ) AS w2
ON w1.sin = w2.sin
AND w1.project_number1 < w2.project_number2;
The little exploit in the requirements here lets us do a natural join and a final projection to finish up ( since I've already renamed the emp_sin
attribute to sin
):
πemp_name, project_number1, project_number2 ( employee ⋈ ( πsin,project_number1 ( ρsin/emp_sin,project_number1/project_number works_on ) ) ⋈sin, project_number1 < project_number2 ( πsin,project_number2 ( ρsin/emp_sin,project_number2/project_number works_on ) ) )
Again, as visual proof, this is approximately the equivalent of the following SQL, shown in action in this SQL Fiddle:
SELECT e.emp_name, w1.project_number1, w2.project_number2
FROM dbo.employee e
INNER JOIN (
SELECT emp_sin
AS sin,
project_number
AS project_number1
FROM dbo.works_on ) AS w1
ON e.sin = w1.sin
INNER JOIN (
SELECT emp_sin
AS sin,
project_number
AS project_number2
FROM dbo.works_on ) AS w2
ON w1.sin = w2.sin
AND w1.project_number1 < w2.project_number2;
Best Answer
DISCLAIMER : Never Learned Relational Algebra but it looks interesting
From the schema given and your question, this is what the SQL should be:
Here is another query that only uses JOINs, no WHERE clause:
The first query gets all employees who are managed and their managers in the form of a Cartesian Product. Then, it looks for a common street and city.
The second query collects personnel records (name,street,city) of employees and their managers and performs a NATURAL JOIN between the employess and their managers using (street,city).
If you can transalate both queries back to Relational Algebra, I think you will have what you are looking for. I believe the second may be of better help.