2015-02-23 92 views
-3

我有這2個表:SQL NOT EXISTS和子查詢

  • Personid, name, address, age
  • KnowspersonA_id, personB_id

,我想返回的Person的名字是比他們知道的Person大5歲以上。

我想這一點:

SELECT 
    P1.name 
FROM 
    Persons P1, Persons P2, Knows K1 
WHERE 
    P1.id = K1.personA_id 
    AND P2.id = K1.personB_id 
    AND NOT EXISTS (SELECT * 
        FROM Persons P3, Persons P4, Knows K2 
        WHERE P3.id = K2.personA_id 
         AND P4.id = K2.personB_id 
         AND (P3.age - P4.age) <= 5) 

但它不工作,我也不太清楚爲什麼。你能指點我正確的方向嗎?在此先感謝

+2

它是如何不工作?你使用的是什麼RDBMS? – 2015-02-23 19:37:26

+1

那麼爲什麼你的意思是「它不工作」? – Lamak 2015-02-23 19:42:50

+0

我的意思是它沒有返回應有的東西。查詢看起來是否正確,我想返回? – eeKat88 2015-02-23 19:43:59

回答

1

如果你真的堅持存在,這可能做的伎倆:

SELECT p1.name AS the_older 
    , p2.name AS the_younger 
FROM Persons p1, Persons p2 
WHERE p1.age - p2.age > 5 -- They are more than 5 years older 
AND EXISTS (    -- than the one they know 
    SELECT * 
    FROM Knows Kx 
    WHERE Kx.personA_id = p1.id AND Kx.personB_id = p2.id 
    ); 

類似的東西可以用完成語法(年齡條件也可以移動到連接條件):

SELECT p1.name AS the_older 
    , p2.name AS the_younger 
FROM Persons p1 
JOIN Persons p2 ON EXISTS (
    SELECT * FROM Knows Kx 
    WHERE Kx.personA_id = p1.id AND Kx.personB_id = p2.id 
    ) 
WHERE p1.age - p2.age > 5 
; 

UPDATE:後澄清的問題:

  • 人物角色必須有一些朋友
  • 所有的他們年齡超過5歲

SELECT p1.name 
FROM Persons p1 
WHERE EXISTS (-- must have friends 
    SELECT * FROM Knows Kx 
    WHERE Kx.personA_id = p1.id 
    ) 
AND NOT EXISTS (-- but no friends less than 5 years younger 
    SELECT * 
    FROM Knows Knx 
    JOIN Persons p2 ON Knx.personB_id = p2.id 
    WHERE Knx.personA_id = p1.id 
    AND p1.age - p2.age <= 5 
     ); 
    ); 
+0

非常感謝。 – eeKat88 2015-02-23 20:25:52

+0

即使我有點得到您的查詢,我仍然不完全明白爲什麼我的不工作 – eeKat88 2015-02-23 20:26:16

+0

請參閱項目符號列表。 (我認爲你的原始查詢未命中第一個項目符號。) – wildplasser 2015-02-23 20:31:13

2

對於每個人,找到他們的年齡和他們認識的每個人的年齡。然後計算他們認識的人的最大年齡和篩選了這一點:

SELECT P1.name 
FROM Persons P1 JOIN 
    Knows K1 
    ON P1.id = K1.personA_id JOIN 
    Persons P2 
    ON P2.id = K1.personB_id 
GROUP BY P1.name, P1.age 
HAVING (p1.age - MAX(p2.age)) > 5; 

雖然你可以做到這一點使用exists,我覺得聚集是一個簡單的查詢和簡單的邏輯。

+0

嗯,我確實使用JOIN的另一個查詢,我也無法得到它與EXISTS工作,但我恐怕我必須做出這個一個不存在。對此有何幫助?我的意思是。你明白我的查詢爲什麼錯了嗎? – eeKat88 2015-02-23 19:52:27

+0

@ GeeKat88你爲什麼'需要'使用'NOT EXISTS'? – Smog 2015-02-23 19:56:15

+1

@Smog因爲這是作業 – Lamak 2015-02-23 19:57:23

1

如果你只需要顯示關係,其中年齡相差> 5

SELECT P1.name 
FROM Persons P1 
INNER JOIN Knows K1 ON P1.id = K1.personA_id 
INNER JOIN Persons P2 ON P2.id = K1.personB_id 
WHERE (P1.age - P2.age) > 5 

,如果你只需要得到所有他們的關係至少有5歲的年齡差異的人則@Gordon Linoff答案是什麼您正在尋找

1

出發點是聯盟都知道表:

SELECT personA_id , 
      personB_id 
FROM  @k k 
UNION 
SELECT personB_id , 
      personA_id 
FROM  @k k 

因爲你會得到不正確的結果,如果你只是從一個側面驗證表知道了。

DECLARE @p TABLE 
    (
     id INT , 
     name NVARCHAR(MAX) , 
     age INT 
    ) 
DECLARE @k TABLE 
    (
     personA_id INT , 
     personB_id INT 
    ) 

INSERT INTO @p 
VALUES (1, 'a', 10), 
     (2, 'b', 14), 
     (3, 'c', 30), 
     (6, 'f', 35), 
     (7, 'g', 45) 


INSERT INTO @k 
VALUES (1, 2), 
     (1, 3), 
     (2, 3), 
     (7, 6) 


SELECT t.personA_id , 
     t.name 
FROM (SELECT personA_id , 
        name , 
        paage - pbage AS diff 
      FROM  (SELECT personA_id , 
           personB_id , 
           pa.age paage , 
           pb.age pbage , 
           pa.name 
         FROM  @k k 
           JOIN @p pa ON pa.id = k.personA_id 
           JOIN @p pb ON pb.id = k.personB_id 
         UNION 
         SELECT personB_id , 
           personA_id , 
           pb.age pbage , 
           pa.age paage , 
           pb.name 
         FROM  @k k 
           JOIN @p pa ON pa.id = k.personA_id 
           JOIN @p pb ON pb.id = k.personB_id 
        ) k 
     ) t 
GROUP BY t.personA_id , 
     t.name 
HAVING (MIN(diff) > 5) 

輸出:

personA_id name 
3   c 
7   g 

如果您將直接加入上表誰知,那麼你將得到:

SELECT t.personA_id , 
     t.name 
FROM (SELECT personA_id , 
        name , 
        paage - pbage AS diff 
      FROM  (SELECT personA_id , 
           personB_id , 
           pa.age paage , 
           pb.age pbage , 
           pa.name 
         FROM  @k k 
           JOIN @p pa ON pa.id = k.personA_id 
           JOIN @p pb ON pb.id = k.personB_id 
        ) k 
     ) t 
GROUP BY t.personA_id , 
     t.name 
HAVING (MIN(diff) > 5) 

輸出:

personA_id name 
7   g