Converting aggregate operators from SQL to relational algebra

前端 未结 3 1667
抹茶落季
抹茶落季 2020-12-18 13:56

I have several SQL queries written that I want to convert to relational algebra. However, some of the queries use aggregate operators and I don\'t know how to convert them.

3条回答
  •  孤城傲影
    2020-12-18 14:19

    Building on onedaywhen's answer:

    Yes, the lack of a set difference operator does hurt. It should totally be allowed. However, we can express set difference with set complement and intersection:

    B - A = B ∩ A'
    

    i.e. the difference of B and A is in fact B's intersection with A's complement. We have the intersection as an allowed operator, and while a relation's proper complement is an ugly thing, the complement of an R1 ⊆ R relative to R (i.e. the stuff in R that aren't in R1) can be found easily with a join:

    SELECT DISTINCT R0.x
    FROM R as R1
    JOIN R as R0 ON R1.x<>R0.x
    WHERE R1.x=val
    

    is the complement relative to R of

    SELECT DISTINCT R.x FROM R WHERE R.x=val
    

    So, here comes a solution to the riddle, I think: it's easy to get all the boats reserved by two or more guys: select all the boats that are in the reserves table, take the cartesian product of the result with itself, then select each row that has different sailor1 and sailor2. In the unwieldy relational algebra notation they taught me:

    π( R.bid ) (
       σ( R.bid=R2.bid and R.sid

    (where π is the projection operator, σ is the selection operator, and ρ is the rename operator)

    This nets the id's of all the boats reserved by two or more people. Now I'm going to get all the boats that were reserved by two or less guys. To do this, I'll select all the boats reserved by three or more guys, and take the set's complement by selecting all the rows from the original table which aren't present in that set. It won't be pretty, but here it goes:

     π(R.bid)(σ(R.bid<>R1.bid)(
        π(R.bid)(R)
          x
        π(R1.bid) (
            σ( R1.bid=R2.bid and R2.bid=R3.bid and R1.sid

    You see, I select all the rows which have the property, then select all the rows from the original table which aren't these, netting us all the rows which don't have the property, here meaning all the boats not reserved by three or more people, the boats reserved by two or less persons.

    To get the boats with exactly two guys reserving them, simply intersect this with the set of boats reserved by more than one guy.

    π( R.bid ) (
       σ( R.bid=R2.bid and R.sidR1.bid)(
           π(R.bid)(R)
             x
           π(R1.bid) (
               σ( R1.bid=R2.bid and R2.bid=R3.bid and R1.sid

    Ugh. It's so ugly it hurts. I wish I knew a nicer notation.

    SQLishly, it might look like this, I think:

    (SELECT DISTINCT R1.bid
      FROM Reserves AS R1 
        JOIN Reserves AS R2 ON R1.bid = R2.bid AND R1.sid < R2.sid
    ) INTERSECT (
    SELECT DISTINCT R.bid
      FROM Reserves AS R1
        JOIN Reserves AS R2 ON R1.bid = R2.bid AND R1.sid < R2.sid
        JOIN Reserves AS R3 ON R1.bid = R3.bid AND R2.sid < R3.sid
        JOIN Reserves AS R ON R.bid<>R1.bid
    )
    

    Please note that this is exactly onedaywhen's solution, except I expressed set difference as taking the intersection with the complement.

提交回复
热议问题