2014-09-25 5 views
0

Я использую MYSQL 5.X, и у меня возникли проблемы с поиском запроса;SQL Select Many to Many

У меня есть 2 объекта со многими отношениями.

клиент и сервис, поэтому у меня есть 3 таблицы:

клиентов, clients_has_services и услуг.

Мне нужно выбрать КАЖДОЕ обслуживание, которое НЕ относится к конкретному клиенту.

например: У меня есть клиент с идентификатором 1 и 4 службы в целом (Service1, Service2, Service3, Service4), клиент 1 имеет отношения с Service1), поэтому мне нужно получить все другие службы (Service2, Service3 , Service4)

Предложения?

ответ

1

Сначала получите комплект services.

Присоедините это к строке от clients для «конкретного клиента», так что у вас есть набор всех услуг для клиента.

«Трюк» заключается в использовании шаблона против объединения, чтобы исключить строки, в которых у вас есть «совпадения» в таблице clients_have_services.

Если у вас есть уникальный идентификатор клиента (и вам нужно только список для одного клиента), что-то вроде этого:

SELECT s.* 
    FROM services s 
    LEFT 
    JOIN clients_have_services h 
    ON h.service_id = s.id 
    AND h.client_id = 42 
WHERE h.service_id IS NULL 
ORDER BY s.id 

внешнее соединение возвращает все строки из services, наряду с любым " сопоставление "строк из таблицы clients_have_services. «Трюк» - это предикат в предложении WHERE, который исключает любые строки, в которых было найдено совпадение, оставив только services, которые не связаны с конкретным клиентом.

Если вы делаете это для нескольких клиентов ... вам нужно также вернуть крест клиента, соединенный с сервисами (как кросс-продукт клиентов и служб), а затем исключить совпадения.

Например:

SELECT c.id AS client_id 
    , s.* 
    FROM clients c 
CROSS 
    JOIN services s 
    LEFT 
    JOIN clients_have_services h 
    ON h.service_id = s.id 
    AND h.client_id = c.id 
WHERE h.service_id IS NULL 
ORDER BY c.id, s.id 

Там есть несколько других шаблоны запросов, которые возвращают эквивалентный результат, например, NOT EXISTS

SELECT s.* 
    FROM services s 
WHERE NOT EXISTS 
     (SELECT 1 
      FROM clients_have_services h 
      WHERE c.client_id = 42 
      AND h.service_id = s.id 
     ) 
ORDER BY s.id 
+0

вы ответите работали ,, но вы ввели в «N» вместо «ч» после И –

+0

Это была опечатка. (На мой взгляд, An n очень похож на h. (По крайней мере, запрос вернул бы ошибку, а не ошибочные результаты.) – spencer7593

+0

ya, ty для объяснения: D thumbs up! –

1

Предполагая, что ваш client_has_services выпрямляет многие-ко-многим, поэтому у вас есть один на много с обеих сторон, поэтому ваши client_has_services должны иметь: ID (ключ), Client_ID, Service_ID

SELECT * FROM services WHERE services.id != ANY (select client_has_services.services_id from client_has_services where client_has_services.client_id = ID_num_provided)

+0

Не будет ли этот запрос ошибка, когда подзапрос возвращает более одной строки? Возможно, если '!= 'сравнение неравенства было заменено оператором' NOT IN', и мы гарантировали, что подзапрос не вернет значение NULL, это сработает. – spencer7593

+0

Если он возвращает более одной строки, это не проблема. Он будет перезапускать «superquery» для каждой возвращаемой строки. Кажется встречным интуитивным, но он работает. – Nick

+0

У вас есть ссылка на это поведение или пример, демонстрирующий его? Я ожидаю, что в вашем ответе появится запрос на повышение ошибки 1242 «Подзапрос возвращает более 1 строки». [Http://dev.mysql.com/doc/refman/5.5/en/subquery-errors.html](http://dev.mysql.com/doc/refman/5.5/en/subquery-errors.html) – spencer7593