2015-02-23 5 views
-3

У меня есть эти 2 таблицы:SQL не было, и подзапрос

  • Person (id, name, address, age)
  • Knows (personA_id, personB_id)

, и я хочу, чтобы вернуть имена Person о том, что на 5 лет старше, чем знают Person.

Я пытаюсь это:

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

Как это не работает? Какие СУБД вы используете? –

+1

, то почему вы имеете в виду, что «это не работает»? – Lamak

+0

Я имею в виду, что он не возвращает то, что предполагается. Правильно ли выглядит запрос на то, что я хочу вернуть? – eeKat88

ответ

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 
    ); 

Нечто подобное можно сделать с помощью JOIN синтаксис (условие возраста также может быть перемещен в состоянии присоединиться):

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

+0

Несмотря на то, что я как бы получаю ваш запрос, я до сих пор не совсем понимаю, почему мой не работает – eeKat88

+0

См. Список пулей. (Я думаю, что ваш первоначальный запрос пропустил первую пулю.) – wildplasser

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

+0

@ GeeKat88 почему вам нужно использовать «НЕТ СУЩЕСТВУЕТ»? – Smog

+1

@Smog Потому что это домашнее задание – Lamak

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 

Если вы присоединитесь прямо на столе Knows, то вы получите:

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