SQL exclude duplicated pairs of columns from a two-column select - sql

I don't really know how to describe my problem and I haven't found an answer.
I have two tables, rating and reviewer. I want to get for every pair of reviewers their names if they rated the same movie.
I have this SQL query:
SELECT DISTINCT re1.name, re2.name
FROM reviewer re1, reviewer re2, rating ra1, rating ra2
WHERE re1.rid=ra1.rid AND re2.rid=ra2.rid AND ra1.mid=ra2.mid AND re1.rid!=re2.rid;
This is the tables structure: rating (rid, mid, stars, ratingdate), reviewer(rid, name)
This is what I want to get:
NAME NAME
Daniel Lewis Elizabeth Thomas
Elizabeth Thomas James Cameron
Ashley White Chris Jackson
Mike Anderson Sarah Martinez
Brittany Harris Chris Jackson
This is what I get:
NAME NAME
------------------------------ ------------------------------
Daniel Lewis Elizabeth Thomas
Elizabeth Thomas James Cameron
Chris Jackson Brittany Harris
Chris Jackson Ashley White
Ashley White Chris Jackson
James Cameron Elizabeth Thomas
Mike Anderson Sarah Martinez
Sarah Martinez Mike Anderson
Elizabeth Thomas Daniel Lewis
Brittany Harris Chris Jackson
How do I remove the duplicate rows where the name1 and name2 have already been selected as name2, name1 ?
I hope I was clear enough. Thanks.

Its a very subtle change (> vs your !=), but what you want to do is use a diagonal elimination approach, whereby you exclude any reviewer with a rid lower than the current one:
SELECT DISTINCT re1.name, re2.name
FROM reviewer re1
INNER JOIN rating ra1
ON re1.rid=ra1.rid
CROSS JOIN
reviewer re2
INNER JOIN rating ra2
ON re2.rid=ra2.rid
WHERE ra1.mid=ra2.mid AND re1.rid > re2.rid;
This way, you don't 'double count' pairs of reviewers which already have a match on the opposite / symmetric side of the diagonal.
I've also taken the liberty of moving the JOIN conditions into JOINs, rather than in the WHERE clause.
SqlFiddle here

This query selects all reviewers of each movie and pairs them up with all other reviewers (whether or not they have reviewed the same movie). It then uses an exists to only keep reviewers that have reviewed the same movie.
select re1.name, re2.name
from reviewer re1 join reviewer re2 on re2.rid < re1.rid
join rating ra1 on ra1.rid = re1.rid
where exists (
select 1 from rating ra2
where ra2.mid = ra1.mid
and ra2.rid = re2.rid
)

Related

SQL join manager from same table onto a row with their employees

To start, here's a dummy table I've made to show the data I'm working with:
employee
title
division
email
Boss Person
boss
o
bp#email
John Smith
supervisor
a
jos#email
Jane Smith
supervisor
b
jas#email
Leo Messi
employee
a
lm#email
Amanda Kessel
employee
a
ak#email
Derek Jeter
employee
b
dj#email
I want to end up with the following info:
employee
title
division
email
supervisor_name
supervisor_email
Boss Person
boss
o
bp#email
NULL
NULL
John Smith
supervisor
a
jos#email
Boss Person
bp#email
Jane Smith
supervisor
b
jas#email
Boss Person
bp#email
Leo Messi
employee
a
lm#email
John Smith
jos#email
Amanda Kessel
employee
a
ak#email
John Smith
jos#email
Derek Jeter
employee
b
dj#email
Jane Smith
jas#email
I've looked through and tried documentation at:
https://www.sqltutorial.org/sql-self-join/
SQL Server : LEFT JOIN EMPLOYEE MANAGER relationship
One of the big differences here is I don't have any employee or manager id column to work with.
If you're a supervisor for a division, ie John Smith is a supervisor in division a, then you manage all the employees in division a. Meanwhile, all the supervisors answer to the boss in division o, while the boss answers to no one.
Here is the best code I've tried so far:
select e.*, b.employee as supervisor, b.email as supervisor_email
from employees e, employees b
where b.division = e.division
and
b.title like '%supervisor%'
This got me close, it returned:
employee
title
division
email
supervisor_name
supervisor_email
John Smith
supervisor
a
jos#email
John Smith
jos#email
Jane Smith
supervisor
b
jas#email
Jane Smith
jas#email
Leo Messi
employee
a
lm#email
John Smith
jos#email
Amanda Kessel
employee
a
ak#email
John Smith
jos#email
Derek Jeter
employee
b
dj#email
Jane Smith
jas#email
So, it got the employee info right, but left out the Boss record and placed the supervisors as their own supervisor. I think I need some kind of case or if statement here, but I'm not sure.
Please let me know if this makes sense or if any further clarification is needed.
You could try using a LEFT JOIN and work with two conditions:
when division is the same and we're dealing with the relationship employee < supervisor
when the relationship is supervisor < boss
Here's how I did it:
SELECT t1.*,
t2.employee,
t2.email
FROM tab t1
LEFT JOIN tab t2
ON (t1.division = t2.division AND
t2.title = 'supervisor' AND
t1.title = 'employee')
OR (t2.title = 'boss' AND
t1.title = 'supervisor')
You'll find an SQL fiddle here.
If you want to update the current table (if columns are available), you can do the following (more or less the same as #lemon) :
UPDATE testing t1 JOIN testing t2 ON t2.`division`=t1.division OR t2.division="o" SET
t1.supervisor_name=t2.`employee`, t1.supervisor_email=t2.email
WHERE (CASE
WHEN t1.`title`="employee" THEN t2.title="supervisor"
WHEN t1.`title`="supervisor" THEN t2.title="boss"
END);
SELECT * FROM testing;

oracle exercise question in my data using 2 table information

person
name home st
JAMES LA L1
MIKE BOSTON B1
ANTON LA L1
LEE NY N1
BROWN NY N2
mentor
name m_name
JAMES ANTON
MIKE (null)
ANTON (null)
LEE BROWN
BROWN (null)
I want to get information from people who live in the same st and cities as mentors.
In the example I gave, it is JAMES who meets that condition.
How could I get that information?..
my version oracle11g
This sounds like two joins:
select pn.name
from mentor m join
person pn
on pn.name = m.name join
person pm
on pm.name = m.m_name
where pn.street = pm.street and pn.city = pm.city;

How to solve this using a subquery in a from clause?

Display author, title, retail and retail price of all books whose retail price is the highest for the specific author.
I have the query below. I'm kinda confused how to do a subquery in a from clause.
select lname, fname, title, retail
from author natural join bookauthor
natural join books
where retail=(select max(retail)
from books);
Below is the data from the database that I'm using
FNAME LNAME TITLE RETAIL
---------- ---------- ------------------------------ ----------
SAM SMITH BODYBUILD IN 10 MINUTES A DAY 30.95
LISA PORTER BODYBUILD IN 10 MINUTES A DAY 30.95
JANICE JONES REVENGE OF MICKEY 22
TAMARA KZOCHSKY BUILDING A CAR WITH TOOTHPICKS 59.95
TINA PETERSON DATABASE IMPLEMENTATION 55.95
JUAN ADAMS DATABASE IMPLEMENTATION 55.95
JAMES AUSTIN DATABASE IMPLEMENTATION 55.95
JACK BAKER COOKING WITH MUSHROOMS 19.95
JAMES AUSTIN HOLY GRAIL OF ORACLE 75.95
LISA WHITE HANDCRANKED COMPUTERS 25
WILLIAM WHITE HANDCRANKED COMPUTERS 25
JANICE JONES E-BUSINESS THE EASY WAY 54.5
ROBERT ROBINSON PAINLESS CHILD-REARING 89.95
OSCAR FIELDS PAINLESS CHILD-REARING 89.95
JACK BAKER PAINLESS CHILD-REARING 89.95
SAM SMITH THE WOK WAY TO COOK 28.75
ROBERT ROBINSON BIG BEAR AND LITTLE DOVE 8.95
SAM SMITH HOW TO GET FASTER PIZZA 29.95
WILLIAM WHITE HOW TO MANAGE THE MANAGER 31.95
LISA WHITE SHORTEST POEMS 39.95
20 rows selected.
You could use this:
SELECT lname, fname, title, retail
FROM author a
INNER JOIN bookauthor ba
ON a.id = ba.author_id
INNER JOIN books b
ON b.id = ba.book_id
WHERE (ba.author_id, ba.retail) IN (
SELECT ba1.author_id, MAX(b1.retail)
FROM books b1
INNER JOIN bookauthor ba1
ON ON b1.id = ba1.book_id
GROUP BY ba1.author_id
);
Do not use NATURE JOIN. This is bad way of join, for all learner and programmer.
(And change author_id, book_id to column name of your specific table)
Other way:
SELECT lname, fname, title, retail
FROM author a
INNER JOIN bookauthor ba
ON a.id = ba.author_id
INNER JOIN books b
ON b.id = ba.book_id
INNER JOIN(
SELECT ba1.author_id, MAX(b1.retail) retail
FROM books b1
INNER JOIN bookauthor ba1
ON ON b1.id = ba1.book_id
GROUP BY ba1.author_id
) mr
ON
ba.author_id = mr.author_id
AND ba.retail = mr.retail
;
This can be solved using ether an inner join:
select lname, fname, title, retail
from author natural join bookauthor
natural join books
inner join (select max(retail) as max_retail, authorid
from books
group by authorid) b
on books.authorid = b.authorid and books.retail = b.max_retail
or a correlated subquery:
select lname, fname, title, retail
from author natural join bookauthor
natural join books
where retail=(select max(retail)
from books b where b.authorid=author.authorid);
Please note, because you are using the natural join it is impossible for us to know the actual column names you used for the joins. Therefore I have assumed that the authorid foreign key is called authorid

SQL Query: How to select multiple instances of a single item without collapsing into a group?

I'm trying to do with following with an SQL query in Impala. I've got a single data table that has (among other things) two columns with values that intersect multiple times. For example, let's say we have a table with two columns for related names and phone numbers:
Names Phone Numbers
John Smith (123) 456-7890
Rob Johnson (123) 456-7890
Greg Jackson (123) 456-7890
Tom Green (123) 456-7890
Jack Mathis (123) 456-7890
John Smith (234) 567-8901
Rob Johnson (234) 567-8901
Joe Wolf (234) 567-8901
Mike Thomas (234) 567-8901
Jim Moore (234) 567-8901
John Smith (345) 678-9012
Rob Johnson (345) 678-9012
Toby Ellis (345) 678-9012
Sam Wharton (345) 678-9012
Bob Thompson (345) 678-9012
John Smith (456) 789-0123
Rob Johnson (456) 789-0123
Kelly Howe (456) 789-0123
Hank Rehms (456) 789-0123
Jim Fellows (456) 789-0123
What I need to get from this table is a selection of each item from the Name column that has multiple entries from the Phone Numbers column associated with it, like this:
Names Phone Numbers
John Smith (123) 456-7890
John Smith (234) 567-8901
John Smith (345) 678-9012
John Smith (456) 789-0123
Rob Johnson (123) 456-7890
Rob Johnson (234) 567-8901
Rob Johnson (345) 678-9012
Rob Johnson (456) 789-0123
This is the query I've got so far, but it's not quite giving me the results I'm looking for:
SELECT a.name, a.phone_number, b.phone_number, b.count1
FROM databasename a
INNER JOIN (
SELECT phone_number, COUNT(phone_number) as count1
FROM databasename
GROUP BY phone_number
) b
ON a.phone_number = b.phone_number;
Any ideas on how to improve my query to get the results I'm looking for?
Thank you.
Working with your query...
This generates a subset by name of users having more than 1 phone number it then joins back to the entire set based on name returning all phone numbers for users having more than 1 phone number. however if a user has the same phone number listed more than once it would get returned. to eliminate those if needed, add distinct to the count in the inline view.
SELECT a.name, a.phone_number
FROM databasename a
INNER JOIN (
SELECT name, COUNT(phone_number) as count1
FROM databasename
GROUP BY name
having COUNT(phone_number) > 1
) b
on a.name = b.name
Order by a.name, a.phone_Number
One method is to use exists:
select t.*
from tablename t
where exists (select 1 from tablename t2 where t2.name = t.name and t2.phonenumber <> t.phonenumber)
SELECT DISTINCT x.*
FROM my_table x
JOIN my_table y
ON y.name = x.name
AND y.phone <> x.phone;

Is it joins again in ORACLE

Here's the problem:
List the title, authors first and last names and year to date sales for books whose authors have addresses in California and Utah.
the desc tables:
SQL> desc authors
Name
--------------------------
AUTHOR_ID
AUTHOR_LNAME
AUTHOR_FNAME
PHONE
ADDRESS
CITY
STATE
ZIP
SQL> desc title_authors
Name
--------------------------
AUTHOR_ID
TITLE_ID
AUTHOR_ORD
ROYALTY_SHARE
SQL> desc titles
Name
--------------------------
TITLE_ID
TITLE
TYPE
PUBLISHER_ID
PRICE
ADVANCE
YTD_SALES
CONTRACT
NOTES
PUBLICATION_DATE
Here's what Ive tried w/ results......
SQL> SELECT AUTHORS.AUTHOR_FNAME, AUTHOR_LNAME, TITLES.TITLE, TITLES.YTD_SALES
2 FROM AUTHORS
3 JOIN TITLE_AUTHORS ON AUTHORS.AUTHOR_ID = TITLE_AUTHORS.AUTHOR_ID
4 JOIN TITLES ON TITLE_AUTHORS.TITLE_ID = TITLES.TITLE_ID
5 WHERE STATE = 'CA'
6 OR STATE = 'UT';
AUTHOR_FNAME AUTHOR_LNAME TITLE YTD_SALES
-------------------- ---------------------------------------- ---------------------------------------- ----------
Marjorie GreeN The Busy Executive's Database Guide 4095
Marjorie GreeN You Can Combat Computer Stress! 18722
Dick StrAight Straight Talk About Computers 4095
Note 3 full results returned.
Next trial, which Ive tried various versions of, returns 3 full records, but the entire authors list:
AUTHOR_FNAME AUTHOR_LNAME TITLE YTD_SALES
-------------------- ------------ ---------------------------------------- ----------
Marjorie GreeN The Busy Executive's Database Guide 4095
Marjorie GreeN You Can Combat Computer Stress! 18722
Dick StrAight Straight Talk About Computers 4095
Albert Ringer
Ann Dull
JOHNSON White
Chastity Locksley
Anne RINGER
Stearns MacFeatHer
Anne RINGER
Michael O'Leary
Stearns MacFeatHer
Livia Karsen
Abraham BeNNet
Albert Ringer
Michael O'Leary
Sheryl Hunter
Cheryl Carson
Chastity Locksley
What is this? Is it blocked somehow? I can see the entire tables individually.
Any one?
Try this,
SELECT AUTHORS.AUTHOR_FNAME, AUTHOR_LNAME, TITLES.TITLE, TITLES.YTD_SALES
FROM AUTHORS
INNER JOIN TITLE_AUTHORS ON AUTHORS.AUTHOR_ID = TITLE_AUTHORS.AUTHOR_ID
INNER JOIN TITLES ON TITLE_AUTHORS.TITLE_ID = TITLES.TITLE_ID
WHERE STATE = 'CA' OR STATE = 'UT';