在 ORACLE DB 中查找具有共同点的对

Finding pairs that share commonalities in ORACLE DB

所以我目前正在努力完成上述任务(大学作业)。

我需要找到两人 (p1.LASTNAME,p2.LASTNAME) 都喜欢同样的鸡尾酒并且至少参加过一次相同的活动。

所需的 Oracle 表是 PERSON 和 VISITED,它们如下所示:

CREATE TABLE PERSON
(
    PID      INT,
    FIRSTNAME  VARCHAR2(255) NOT NULL,
    LASTNAME VARCHAR2(255) NOT NULL,
    FAVCOCKTAIL INT,
    PRIMARY KEY (PID),
    FOREIGN KEY (FAVCOCKTAIL) REFERENCES COCKTAIL (CID)
);

CREATE TABLE VISITED
(
    PID INT,
    VID INT,
    FOREIGN KEY (PID) REFERENCES PERSON (PID),
    FOREIGN KEY (VID) REFERENCES VISITED (VID)
);

到目前为止,这是我的方法:

SELECT DISTINCT P1.LASTNAME, P2.LASTNAME, B1.VID, B2.VID, P1.FAVCOCKTAIL, P2.FAVCOCKTAIL
FROM PERSON P1,
     PERSON P2,
     VISITED B1,
     VISITED B2
WHERE P1.FAVCOCKTAIL = P2.FAVCOCKTAIL
  AND B1.VID = B2.VID
  AND P1.LASTNAME != P2.LASTNAME;

现在每当我读到“至少一次”时,我都在考虑使用我尝试过的 COUNT 函数,但我无法让它工作,我尝试过的几个 JOIN 方法也是如此。

我确信这个问题有一个优雅的解决方案。我的方法在某种意义上更像是“蛮力”。

不胜感激!

为了简单起见(CTE 中的样本数据我稍后会 post,因为你没有提供任何数据),我正在创建一个简单的视图,将他们访问过的人和地方连接起来(将 VID 更改为 可读):

create or replace view v_view as
  select p.pid, p.lastname, p.favcocktail, v.vid
  from person p join visited v on v.pid = p.pid;

那么,如果你这样做,你可能会得到结果:

SQL> with v_view (pid, lastname, favcocktail, vid) as
  2    (select 1, 'Scott', 'Pepsi', 'London' from dual union all
  3     select 2, 'King' , 'Pepsi', 'London' from dual union all
  4     select 3, 'Mike' , '7up'  , 'London' from dual union all
  5     select 4, 'John' , 'Pepsi', 'Paris'  from dual
  6    )
  7  select listagg(a.lastname, ', ') within group (order by null) people,
  8         a.favcocktail,
  9         a.visited
 10  from v_view a join v_view b on a.pid <> b.pid
 11    and a.favcocktail = b.favcocktail
 12    and a.vid = b.vid
 13  group by a.favcocktail,
 14           a.visited;

PEOPLE                         FAVCOCKTAIL     VID
------------------------------ --------------- ---------------
King, Scott                    Pepsi           London

SQL>

或者,不将示例数据和视图移入 CTE(以便您可以立即执行):

with v_view as
  (select p.pid, p.lastname, p.favcocktail, v.vid
   from person p join visited v on v.pid = p.pid
  )
select listagg(a.lastname, ', ') within group (order by null) people, 
       a.favcocktail, 
       a.vid
from v_view a join v_view b on a.pid <> b.pid
  and a.favcocktail = b.favcocktail
  and a.vid = b.vid
group by a.favcocktail,
         a.vid;