2017-02-16 16 views
0

だから、私は同じセレブとの関係にあった有名人をリストするSQLでクエリを書く必要があります。私は基本的にceleb1、celeb2、およびceleb3をリストアップしています。ここで、celeb3はceleb1とceleb2の両方との関係にあります。ここで私が使用しているクエリです:SQL結果に重複行がある場合

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の関係をリストしていますが、逆のceleb2、celeb1もリストしているためです。どうすれば結果が重複しているのを防ぐことができますか?

ここに私がこれを行うために使用している2つのテーブル(リレーションシップとセレブ)があります。

CREATE TABLE Celebs(
    name VARCHAR(30) 
); 

CREATE TABLE Relationships (
    Celeb1 VARCHAR(30), 
    Celeb2 VARCHAR(30) 
); 
+2

今日のヒント:現代的で明示的な 'JOIN'構文に切り替えます。書き込みが簡単(エラーなし)、読みやすく保守が容易、必要に応じて外部結合に変換する方が簡単です。 – jarlh

+0

これは私が持っている問題を解決するのに役立つでしょうか? –

+0

いいえ、しかし、あなたのSQL知識を次のレベルに! – jarlh

答えて

0

Celeb3がAとBとの関係にある場合、結果としてB、Aも得られます。

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 
+0

それは動作しません私はまだ重複する行を取得しています。 –

+0

'disctinct'節を追加...私の答えを編集する –

+0

私の結果は598行、私の関係テーブルは425行ありますが、それは動作しているようです。 598行がやや高いように見えますか?また、私がA <> Bを代わりに実行すると、1198行が得られます。何故ですか? –

1

のサンプルを見てみましょう:

 
celeb1 celeb2 
A  B 
B  C 
C  D 

期待される結果:

  • AとCはBとの両方だったことを避けるために、ちょうどA> Bが制約を作ります
  • BおよびDはともにCであった。

これらの一致を見つけるために、私はタプルを複製することをお勧めします。

 
celeb1 celeb2 
A  B 
B  A 
B  C 
C  B 
C  D 
D  C 

すでにBとCにそれぞれ2つのパートナーがあることがわかります。このデータセットを自分自身と結合して、レコードを接続します。

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; 
+0

これはそれです。私はまったく同じUNIONアプローチから始めて、それをローカルで検証しようとしていましたが、私のSQL開発者はスタート時にクラッシュしていました。よくできました。 –

+0

私が用意したデータでこのアプローチをMySQLに適用http://sqlfiddle.com/#!9/0933ef/5 –

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句変更:あなたはその後、グループがこのちょうど得るためにLISTAGGを使用でき

ON ( (c.name = r.celeb1 AND c.name < r.celeb2) 
    OR (c.name = r.celeb2 AND c.name < r.celeb1)) 

クエリ2を人ごとに1つの行:

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; 

出力

関連する問題