Это сложная проблема, о которой я почти хочу сказать «не пытайтесь сделать это одним запросом».
Я подхожу к SQL-запросам, как это, с точки зрения программирования, так как я чувствую, чторезультаты имеют тенденцию быть менее "волшебными".(Свойство, которое я вижу в слишком многих запросах - кажется, что запросы SQL в наши дни пишутся с использованием обезьян на клавиатурах…)
- Выясните, какие идентификаторы компании мы хотим перечислить.Это объединение этих двух вещей:
- Любые результаты "людей" совпадают по имени или номеру
- Любые результаты "компании" совпадают по имени или номеру
- Укажите номер этой компании, а также людей.
Давайте сначала сделаем # 2:
SELECT
companyname AS name,
phone
FROM
customers
WHERE id IN (company_ids we want)
UNION
SELECT
name, phone
FROM
contacts
WHERE companyid IN (company_ids we want)
Поскольку "company_ids мы хотим" будетбудьте запросом, переставьте это, чтобы свести его к одному вхождению:
SELECT
name, phone
FROM
(
SELECT
id AS companyid,
companyname AS name,
phone
FROM
customers
UNION
SELECT companyid, name, phone FROM contacts
) AS entities
WHERE
companyid IN (company_ids we want)
Теперь, чтобы заполнить интересную часть, нам нужно ответить # 1:
Часть # 1.1:
SELECT companyid FROM contacts WHERE name = $search OR number = $search;
Часть # 1.2:
SELECT id AS companyid FROM customers WHERE companyname = $search OR number = $search;
(Обратите внимание, что $search
- это наши входные параметризованные запросы сильно отличаются от одного поставщика SQL к другому, поэтому замените этот синтаксиспо мере необходимости.)
Поместите UNION
из этих двух в IN
, и мы закончили:
SELECT
name, phone
FROM
(
SELECT
id AS companyid,
companyname AS name,
phone
FROM
customers
UNION
SELECT companyid, name, phone FROM contacts
) AS entities
WHERE
companyid IN (
SELECT companyid FROM contacts WHERE name = $search OR phone = $search
UNION
SELECT id AS companyid FROM customers WHERE companyname = $search OR phone = $search
)
;
И молитесь, чтобы база данных могла выяснить план запроса, которыйвыполняет это в разумные сроки.Уверены, что не хотите заходить в БД несколько раз?
Обратите внимание на методологию: мы определили, что нам нужно («имена / телефоны для клиентов / контакты, соответствующие определенным компаниям»), а затем выяснилинедостающий кусок («какие компании идентификаторы?»).Это происходит из-за того, что после того, как вы сопоставите конкретного человека в компании (скажем, Сэма), вы захотите всех из этой компании плюс компания или все с этим идентификатором компании.Зная это, мы получаем наш внешний запрос (# 2), а затем нам просто нужно выяснить, как определить, какие компании нас интересуют.
Обратите внимание, что это не будет (и запросы SQL, безORDER BY не) возвращать запросы в вашем довольно причудливом порядке.Однако вы можете добавить вспомогательный столбец к внутреннему запросу и выполнить это:
SELECT
name, phone
FROM
(
SELECT
0 AS is_person,
id AS companyid,
companyname AS name,
phone
FROM
customers
UNION
SELECT 1 AS is_person, companyid, name, phone FROM contacts
) AS entities
WHERE
companyid IN (
SELECT companyid FROM contacts WHERE name = $search OR phone = $search
UNION
SELECT id AS companyid FROM customers WHERE companyname = $search OR phone = $search
)
ORDER BY
companyid, is_person, name
;
Вы также можете использовать столбец is_person
(если вы добавите его в SELECT
), если вам нужноСегментируйте результаты так, чтобы получались результаты этого запроса.
(И если вы в конечном итоге будете использовать запросы такой длины, пожалуйста, ради любви к Богу, -- comment them!
)