Query 6: Find pairs of drinkers who frequent EXACTLY the same set of bars.
DRC - Initial Attempt
{X,Y | drinker(X) and drinker(Y) and X<Y and
(forall B)(frequents(X,B) --> frequents(Y,B)) and
(forall B)(frequents(Y,B) --> frequents(X,B)) }
DRC - Removing forall and -->
{X,Y | drinker(X) and drinker(Y) and X<Y and
not ((exists B)(frequents(X,B) and not (frequents(Y,B)))) and
not ((exists B)(frequents(Y,B) and not (frequents(X,B)))) }
DRC - Above query is not safe (inner sub-conjuncts have unlimited variables) - Add Predicates
{X,Y | drinker(X) and drinker(Y) and X<Y and
not ((exists B)(frequents(X,B) and drinker(Y) and not (frequents(Y,B)))) and
not ((exists B)(drinker(X) and frequents(Y,B) and not (frequents(X,B)))) }
DRC Expression Tree
Datalog Conversion at maximal sub-conjuncts
// Maximal sub-conjunct
// (exists B)(frequents(X,B) and drinker(Y) and not frequents(Y,B))
// produces following rule
temp1(X,Y) :- frequents(X,B), drinker(Y), not frequents(Y,B).
// Maximal sub-conjunct
// (exists B)(drinker(X) and frequents(Y,B) and not frequents(X,B))
// produces following rule
temp2(X,Y) :- drinker(X), frequents(Y,B), not frequents(X,B).
// Maximal sub-conjunct
// drinker(X) and drinker(Y) and X<Y and
// not ((exists B)(frequents(X,B) and not frequents(Y,B))) and
// not ((exists B)(frequents(Y,B) and not frequents(X,B)))
// produces following rule
answer(X,Y) :- drinker(X), drinker(Y), X<Y, not temp1(X,Y), not temp2(X,Y).
Since temp1(X,Y) is equivalent to temp2(Y,X), we can simplify the Datalog
query to:
temp(X,Y) :- drinker(X), frequents(Y,B), not frequents(X,B).
answer(X,Y) :- drinker(X), drinker(Y), X<Y, not temp(X,Y), not temp(Y,X).
Relational Algebra (RA)
select[X<Y](
rename[X](drinker)
join
rename[Y](drinker)
join
((rename[X](drinker) times rename[Y](drinker))
minus
project[X,Y](rename[X,B](frequents) join rename[Y](drinker) join
((rename[Y](drinker) times project[B](rename[X,B](frequents)))
minus
rename[Y,B](frequents))
)
)
join
((rename[X](drinker) times rename[Y](drinker))
minus
project[X,Y](rename[X](drinker) join rename[Y,B](frequents) join
((rename[X](drinker) times project[B](rename[Y,B](frequents)))
minus
rename[X,B](frequents))
)
)
);
OurSQL Solution
select x.dname, y.dname
from drinker x, drinker y
where x.dname < y.dname and
not exists (
select b.bname
from bar b, frequents f1
where f1.dname=x.dname and
f1.bname=b.bname and
not exists (
select f2.dname
from frequents f2
where f2.dname=y.dname and
f2.bname=b.bname)) and
not exists (
select b.bname
from bar b, frequents f1
where f1.dname=y.dname and
f1.bname=b.bname and
not exists (
select f2.dname
from frequents f2
where f2.dname=x.dname and
f2.bname=b.bname));