开发者

Simple SQL question with subqueries

I'm refreshing my SQL with the online Stanford database class exercises, found here.开发者_Go百科 Here is the problem:

"Find names and grades of students who only have friends in the same grade. Return the result sorted by grade, then by name within each grade."

We have a highschooler table, with the attributes name, grade, id. Also, the likes table has attributes id1 and id2. id1 and id2 in likes correspond to id in highschooler.

Based on the problem section this comes from, I can tell that I'll need to use subqueries, but I'm not sure where. How should I approach this problem? None of the currently suggested solutions work.

Here is my current SQL statement, that is not working correctly (ignoring sorting):

select distinct 
  student1.id, 
  student1.name, 
  student1.grade 
from 
  highschooler student1, 
  highschooler student2, 
  friend 
where not exists (select * 
                  from friend 
                  where student1.id = id1 
                    and student2.id = id2 
                    and student1.grade = student2.grade 
                    and student1.id <> student2.id);


I assumed that, if A was B's Friend, it's equal to B was A's friend.

CREATE VIEW Temp
AS
    SELECT id,name,grade,id2,[grd2] FROM highschooler 
        INNER JOIN Likes ON highschooler.id = Likes.id1         
        INNER JOIN (SELECT id as [id2t], grade as [grd2] from highschooler) a ON a.id2t = Likes.id2             
    UNION ALL 
    SELECT id,name,grade,[id1] as [id2],[grd2] FROM highschooler 
        INNER JOIN Likes ON highschooler.id = Likes.id2         
        INNER JOIN (SELECT id as [id2t], grade as [grd2] from highschooler) a ON a.id2t = Likes.id1     

The temp view let me have all the info i need.

CREATE VIEW PlayWithClassMate 
AS 
    SELECT distinct id FROM Temp WHERE grade = grd2

This PlayWithClassMate view let me have all student who play with her/his classmate (some how, i think a person can play, with all his/her friend not their classmate).

CREATE VIEW IDResult 
AS 
    SELECT id FROM (
        SELECT id, COUNT(GRD2) as c FROM TEMP 
            WHERE id in (SELECT id FROM PlayWithClassMate)
            GROUP BY ID) A
    WHERE C>1

this IDResult view have all the id the question ask you. Now, select whatever you need, inwhich its ID in IDResult

i think it's not the best, or it may be the worst, but it work. (srr abt terribe grammar)


This is harder than it looks, because it requires preparing sets sequentially. But, there are a few ways to solve this one. Here's what quickly comes to mind:

First, find the friend-of-friend for everybody by grade producing something like:

[ID], [FoF ID], [Grade of FoF]

You really don't need [FoF ID], but it might help when debugging.

Then, as a second-order operation, you'll need to produce a list of [ID]s where [Grade of FoF] is equal to both the MAX() and MIN():

SELECT [ID], MAX(Grade of FoF) as A, MIN(Grade of FoF) as B FROM [the above] WHERE A=B

UPDATE: I realized that I should also add that in the final qry: A=B and A=Grade. Then this solution works. Keep in mind: it only answers the question "Find names and grades of students who only have friends in the same grade." and it assumes friendship is one-directional. (Sorry, I had to leave something undone.)

For those that need to see some SQL, here you are. It's written for MS Access, but easily ported (start by removing the "()" in the inner-most query) to MySQL, PGSQL, or Oracle. Better still, no procedural extensions and no temp tables.

SELECT name FROM ( SELECT ID ,name ,grade ,min( friend_grade) as min_friend_grade ,max( friend_grade) as max_friend_grade FROM ( SELECT hs1.ID ,hs1.name ,hs1.grade ,l.ID2 as friend_id ,hs2.name as friend_name ,hs2.grade as friend_grade

FROM ( highschooler hs1 INNER JOIN likes l ON (hs1.ID = l.ID1) ) INNER JOIN highschooler hs2 ON (l.ID2 = hs2.ID)

)FoF

GROUP BY ID ,name ,grade

)FoF_max_min

WHERE grade=min_friend_grade AND min_friend_grade=max_friend_grade

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜