2015-01-19 4 views
2

У меня есть две таблицы, PERSON и ДРУЗЬЯ. ДРУЗЬЯ имеет поля NAME и FURNAME.SQL Query JOIN или IN оператор?

У человека есть N друзей.

Я хочу получить всех ЧЕЛОВЕК, у которых есть по крайней мере два ДРУГА, один с именем = «отметка», а другой с именем = «rocco» и фамилия = «siffredi».

Пример: если у меня есть человек, у которого есть 5 друзей, один из них называется меткой, и никто не называется rocco siffredi, таблицы не возвращаются.

Я думал о:

SELECT * FROM person p 
     JOIN friends AS f ON p.ID=f.personID 
WHERE f.name ="mark" AND f IN 
      (SELECT * from FRIENDS WHERE name="rocco" and surname="siffredi") 

или

SELECT * FROM person p 
     JOIN friends AS f1 ON p.ID=f1.personID 
     JOIN friends AS f2 ON p.ID=f2.personID 
WHERE f1.name="mark" AND f2.name="rocco" AND f2.surname="siffredi" 

Что является лучшим способом? Я имею в виду самый быстрый способ его выполнения. Меня не интересует читаемость. Есть ли другой способ выполнить этот запрос? Ty.

EDIT: добавлен присоединиться на ID ...

+1

Что означает «лучший»? Для удобочитаемости я бы использовал 'WHERE EXISTS (... name =" mark ") И EXISTS (... name. =" Rocco "AND surname =" siffredi ")'. – adrianm

+1

FK должен быть наоборот. Если FK находится на таблице «Человек», каждый человек может иметь только одного друга. –

+0

Отредактировано FK. отредактировал предназначенный "лучший" – Gaetano

ответ

3

я должен был угадать ваши имена столбцов и составляют таблицу:

Использование EXISTS:

CREATE table FRIENDS(person_id INT, friend_id INT) 

go 

SELECT * 
FROM person 
WHERE 
    EXISTS 
    (SELECT * 
    FROM friends f 
    JOIN person per 
    ON f.friend_id = per.id 
    WHERE 
     per.name ='mark' AND 
     person.id = f.person_id) AND 
    EXISTS 
    (SELECT * 
    FROM friends f 
    JOIN person per 
    ON f.friend_id = per.id 
    WHERE 
     per.name = 'rocco' AND 
     per.surname='siffredi' AND 
     person.id = f.person_id) 
+1

Ваш второй существующий никогда не вернет ничего, потому что per.name не может быть Mark и Rocco в то же время. – Spock

+0

@Spock хорошо замечен, я скопировал и вставил слишком много, было исправлено –

+0

Какая разница с моим вторым предлагаемым запросом? – Gaetano

3

Ваша конструкция схемы не очень хорошо для того, что вы пытаетесь сделать ... Я бы таблицу Person, как у вас есть, что бы также содержат уникальный идентификатор PersonId. Тогда у меня была бы таблица друзей, в которой было бы два поля - Person1Id и Person2Id.

Это дает вам несколько важных преимуществ - прежде всего, ваша система может обрабатывать более одного парня под названием Джон Смит (потому что мы присоединяемся к идентификаторам, а не к именам ...). Во-вторых, детали человека записываются только в таблице Person. Одно определение истины ...

+0

Я думал, что идентификаторы там, где явно есть. позвольте мне отредактировать ответ. – Gaetano

+0

* вопрос^ – Gaetano

1

С помощью этих данных в качестве входных данных:

INSERT INTO Person VALUES 
(1, 'Bob', 'Smith'), 
(2, 'Jim', 'Jones') 

INSERT INTO Friends VALUES 
(1, 1, 'Mark', 'Tally'), 
(2, 1, 'John', 'Smith'), 
(3, 1, 'Jack', 'Pollock'), 
(4, 2, 'Mark', 'Rush'), 
(5, 2, 'Rocco', 'Siffredi'), 
(6, 2, 'Mark', 'Bush') 

вы можете использовать этот запрос:

SELECT PersonId, COUNT(*) AS NoOfFriends 
FROM (
    SELECT DISTINCT PersonId, Name, 
      Surname = CASE WHEN NAME = 'Mark' THEN NULl 
         ELSE Surname 
        END 
    FROM Friends 
    WHERE Name = 'Mark' OR (Name = 'Rocco' AND Surname = 'Siffredi')) t 
GROUP BY PersonId 

, чтобы получить четкое количество требуемых друзей в PersonID:

PersonId NoOfFriends 
------------------------ 
1   1 
2   2 

Теперь вы можете присоединиться к выше табличного выражения на PersonId и фильтровать его NoOfFriends:

SELECT p.* 
FROM Person AS p 
INNER JOIN (
    SELECT PersonId, COUNT(*) AS NoOfFriends 
    FROM (
     SELECT DISTINCT PersonId, Name, 
      Surname = CASE WHEN NAME = 'Mark' THEN NULl 
         ELSE Surname 
         END 
     FROM Friends 
     WHERE Name = 'Mark' OR (Name = 'Rocco' AND Surname = 'Siffredi')) t 
    GROUP BY PersonId) s ON s.PersonId = p.ID 
WHERE s.NoOfFriends = 2 

так, чтобы получить только лица, имеющие (а) заинтересован (-а) в этой компании:

ID Name Surname 
------------------- 
2 Jim  Jones 

PS Я полностью переписал свой ответ после комментария @ t-clausen.dk.

+1

не получится, если у человека было 2 друга по имени mark –

+0

@ t-clausen.dk Вы, к сожалению, правы! –

+0

@ t-clausen.dk Вы можете посмотреть мой новый ответ, если хотите. Думаю, сейчас это работает нормально, хотя я не уверен, что он эффективнее вашего решения. –