SQL查询结果有重复行的位置

时间:2017-02-16 08:21:16

标签: sql oracle

所以我必须在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)
);

3 个答案:

答案 0 :(得分:1)

让我们看一个样本:

celeb1  celeb2
A       B
B       C
C       D

预期结果:

  • A和C都是B。
  • B和D都是C。

为了找到这些匹配,我建议复制元组,使得每对夫妇在表中两次(如果不是这样的话)。

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