关系代数 - sql(常用运算符)

Relational algebra - sql (common operators)

我有这些关系方案:

Participate (FestivalName, Artist)
Attend(ID, FestivalName)
Prefer (ID, FestivalName)
Like (ID, Artist) 

I would like to list the people which only attend festivals that are not of their preference and that at the same time, in one of those festivals, at least two artists that they like participated (so, 2 or more). Finally, show the ID and the festival.

我想用常用的运算符来解决这个问题:

selection operator, projection operator, union operator, difference operator and cartesian product

这是一个例子:

ATTEND TABLE
147|HannaBalusa |
147|FestivalTOP |
147|BestFestival|

PREFER TABLE
147|FestivalTOP|

LIKE TABLE
147|PaulMackarney|
147|BobDeylan    |

PARTICIPATE TABLE
HannaBalusa |PaulMackarney |
HannaBalusa |BobMurley     |
FestivalTOP |BobDeylan     |
BestFestival|PaulMackarney |
BestFestival|BobDeylan     |

所以,我应该得到这个输出:

147|BestFestival

我可以使用 SQL 解决这种情况,但我在使用关系代数时遇到问题。

可以帮我吗?

执行您想要的操作的惯用 SQL 查询可能看起来像这样,但是它使用的 SQL 功能比您列出的要多。

SELECT A.ID, A.FestivalName
FROM Attend A
JOIN Participate P 
ON A.FestivalName = P.FestivalName --Adds rows with artists for each attended festival
JOIN Like L 
ON L.ID = A.ID AND L.Artist = P.Artist --Leaves only rows with `Like`d artists
WHERE NOT EXISTS (
  SELECT 1 
  FROM Prefer Pr 
  WHERE Pr.ID = A.ID AND Pr.FestivalName = A.FestivalName
) --Removes people who have ever attended a prefered festival
GROUP BY A.ID, A.FestivalName --Allows to count liked artists per festival 
HAVING COUNT(L.Artist) >= 2 --Leaves only festivals with 2 or more liked artists 

用你描述的操作来完成,它可能看起来像这样

SELECT DISTINCT S1.ID, S1.FestivalName
FROM (
  SELECT A.ID, A.FestivalName, P.Artist
  FROM Attend A
  CROSS JOIN Participate P  
  CROSS JOIN Like L 
  WHERE A.FestivalName = P.FestivalName --Rows with artists for each attended festival 
  AND L.ID = A.ID AND L.Artist = P.Artist --Leaves only rows with `Like`d artists
) S1
CROSS JOIN ( -- Copy of the first subquery
  SELECT A.ID, A.FestivalName, P.Artist
  FROM Attend A
  CROSS JOIN Participate P  
  CROSS JOIN Like L 
  WHERE A.FestivalName = P.FestivalName
  AND L.ID = A.ID AND L.Artist = P.Artist 
) S2
WHERE S1.ID = S2.ID 
AND S1.FestivalName = S2.FestivalName 
AND S1.Artist != S2.Artist --Removes festivals with only 1 liked artist

MINUS -- Remove all rows with people who ever attended prefered festivals

SELECT ID, FestivalName 
FROM ( --People who attended prefered festivals
  SELECT DISTINCT A.ID
  FROM Attend A
  CROSS JOIN Prefer P
  WHERE A.ID = P.ID AND A.FestivalName = P.FestivalName
) 
CROSS JOIN ( -- All existent festivals
  SELECT FestivalName
  FROM Attend
)