所以我必须在SQL中编写一个查询,列出与同一名人有关系的名人。我基本上列出了celeb1,celeb2和celeb3,其中celeb3与celeb1和celeb2有关系。以下是我使用的查询:
SELECT S1.Celeb1, S2.Celeb2, S3.name AS Celeb3
FROM Relationships S1, Relationships S2, Celebs S3
WHERE S3.name = S1.Celeb2
AND S3.name = S2.Celeb1
AND S1.Celeb1 <> S2.Celeb2;
很难知道这个查询是否正确,因为它在结果中给了我200行,但我看了几行,看起来它给了我正确的结果,其中celeb3与celeb1和2都存在关系。问题是结果中有重复的行。这可能是因为在关系表中,它列出了celeb1,celeb2关系,但它也列出了逆名人2,celeb1。那么如何防止结果列出重复项呢?
以下是我用来执行此操作的两个表(Relationships and Celebs)。
CREATE TABLE Celebs(
name VARCHAR(30)
);
CREATE TABLE Relationships (
Celeb1 VARCHAR(30),
Celeb2 VARCHAR(30)
);
答案 0 :(得分:1)
让我们看一个样本:
celeb1 celeb2 A B B C C D
预期结果:
为了找到这些匹配,我建议复制元组,使得每对夫妇在表中两次(如果不是这样的话)。
celeb1 celeb2 A B B A B C C B C D D C
我们已经可以看到B和C各有两个伙伴。加入此数据集以连接记录。
with rel as
(
select celeb1 as cel1, celeb2 as cel2 from relationships
union
select celeb2 as cel1, celeb1 as cel2 from relationships
)
select rel1.cel2 as celeb1, rel2.cel2 as celeb2, rel1.cel1 as partner
from rel rel1
join rel rel2 on rel2.cel1 = rel1.cel1 and rel2.cel2 > rel1.cel2
order by 1, 2, 3;
答案 1 :(得分:0)
如果Celeb3与A和B有关系,那么你也会获得B,A。为避免这种情况,只需制定A&gt;的约束即可。 B:
SELECT DISTINCT S1.Celeb1, S2.Celeb2, S3.name AS Celeb3
FROM Relationships S1, Relationships S2, Celebs S3
WHERE S3.name = S1.Celeb2
AND S3.name = S2.Celeb1
AND S1.Celeb1 > S2.Celeb2
答案 2 :(得分:0)
Oracle安装程序:
CREATE TABLE celebs ( name ) AS
SELECT 'A' FROM DUAL UNION ALL
SELECT 'B' FROM DUAL UNION ALL
SELECT 'C' FROM DUAL UNION ALL
SELECT 'D' FROM DUAL;
CREATE TABLE relationships ( celeb1, celeb2 ) AS
SELECT 'A', 'B' FROM DUAL UNION ALL
SELECT 'B', 'C' FROM DUAL UNION ALL
SELECT 'C', 'D' FROM DUAL;
<强>查询强>:
SELECT DISTINCT
c.name,
CASE c.name WHEN r.celeb1 THEN r.celeb2 ELSE r.celeb1 END AS has_relationship_with
FROM celebs c
LEFT OUTER JOIN
relationships r
ON ( c.name = r.celeb1 OR c.name = r.celeb2 );
<强>输出强>:
NAME HAS_RELATIONSHIP_WITH
---- ---------------------
A B
B A
B C
C B
C D
D C
如果您想A,B
而不想要反B,A
,请将联接的ON
子句更改为:
ON ( ( c.name = r.celeb1 AND c.name < r.celeb2 )
OR ( c.name = r.celeb2 AND c.name < r.celeb1 ) )
查询2 :
然后,您可以使用LISTAGG
对此进行分组,以便每人获得一行:
SELECT name,
LISTAGG( rel, ',' ) WITHIN GROUP ( ORDER BY rel ) AS has_relationship_with
FROM (
SELECT DISTINCT
c.name,
CASE c.name WHEN r.celeb1 THEN r.celeb2 ELSE r.celeb1 END AS rel
FROM celebs c
LEFT OUTER JOIN
relationships r
ON ( c.name = r.celeb1 OR c.name = r.celeb2 )
)
GROUP BY name;
<强>输出强>:
NAME HAS_RELATIONSHIP_WITH
---- ---------------------
A B
B A,C
C B,D
D C