Застрял на MySQL вложенного оператора select - PullRequest
0 голосов
/ 29 августа 2018

У меня есть три таблицы, к которым я присоединяюсь в операторе выбора:

Структура таблицы CRM_CONTACTS:

CONTACTS_ID, CONTACTS_EMAIL
1            email@email.com
2            email2@email.com

Структура таблицы CRM_PRODUCTS:

PRODUCTS_ID, PRODUCTS_NAME, PRODUCTS_TYPE
204          Sample         free_sample
205          beginners_1    monthly_subscription
206          beginners_2    monthly_subscription  

Таблица CRM_PRODUCTS_PURCHASE:

ID, CONTACTS_ID, PRODUCTS_ID
3   1            204
4   1            205
5   2            204

Таким образом, клиенты, конечно, могут купить несколько продуктов.

Я хотел бы сделать заявление о выборе, которое выбирает всех клиентов, которые купили PRODUCT_ID 204 (бесплатный образец), но я не хочу, чтобы они были в моем результате, если они купили продукт PRODUCT_TYPE = month_subscription

Итак, мой ожидаемый результат - контакт с CONTACTS_ID 2.

Я довольно новичок в SQL-заявлениях. Вот что я получил до сих пор:

    SELECT CRM_PRODUCTS_PURCHASE.CONTACTS_ID,CRM_PRODUCTS_PURCHASE.PRODUCTS_ID, CRM_CONTACTS.CONTACTS_EMAIL, CRM_CONTACTS.CONTACTS_LANGUAGE
FROM CRM_PRODUCTS_PURCHASE
LEFT JOIN CRM_CONTACTS ON CRM_PRODUCTS_PURCHASE.CONTACTS_ID = CRM_CONTACTS.ID
LEFT JOIN CRM_PRODUCTS ON CRM_PRODUCTS_PURCHASE.PRODUCTS_ID = CRM_PRODUCTS.ID
WHERE CRM_PRODUCTS_PURCHASE.CONTACTS_ID IN 
(SELECT CRM_CONTACTS.ID
    FROM CRM_PRODUCTS_PURCHASE
        LEFT JOIN CRM_CONTACTS ON CRM_PRODUCTS_PURCHASE.CONTACTS_ID = CRM_CONTACTS.ID
        LEFT JOIN CRM_PRODUCTS ON CRM_PRODUCTS_PURCHASE.PRODUCTS_ID = CRM_PRODUCTS.ID
    WHERE CRM_PRODUCTS_PURCHASE.PRODUCTS_ID = 204 AND
        CRM_CONTACTS.CONTACTS_EMAIL!='' AND
        NOT coalesce(CRM_CONTACTS.CONTACTS_DEACTIVATED,0)
        GROUP BY CRM_CONTACTS.CONTACTS_EMAIL
        ORDER BY CRM_CONTACTS.CONTACTS_LANGUAGE)

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Вы должны избегать вложенных вложенных выборок, где это возможно, поскольку они трудны для работы внутреннего оптимизатора MySQL и, следовательно, имеют тенденцию генерировать очень медленные запросы. Во многих случаях часто лучше создать промежуточную таблицу с данными суб-выбора и присоединиться к ней, чем сделать суб-выбор, но это довольно ситуативно.

Однако иногда вам нужно, и в этих случаях старайтесь сделать суб-выбор максимально простым.

SELECT *
FROM CRM_PRODUCTS_PURCHASE
   # Do other joins 
WHERE
    CRM_PRODUCTS_PURCHASE.CONTACTS_ID NOT IN (
        SELECT CONTACTS_ID
        FROM CRM_PRODUCTS_PURCHASE
        WHERE
            CRM_PRODUCTS_PURCHASE.PRODUCTS_ID IN (205, 206))
    AND CRM_PRODUCTS_PURCHASE.PRODUCTS_ID = 204
;

- Выше не проверено

ПРИМЕЧАНИЕ: ORDER BY в дополнительном выборе обычно не имеет никакого эффекта. Оставьте ORDER BY до последнего, т.е. mysql - упорядочить по внутреннему подзапросу

В наших случаях из реального мира мы часто обнаруживали, что было бы на порядок лучше выполнить вышеупомянутые два запроса. т.е. создать список CONTACTS_ID и сохранить значение в переменной PHP, а затем выполнить второй запрос, который использовал эти значения в предложении NOT IN.

0 голосов
/ 29 августа 2018

Прежде всего вы упомянули ORDER BY CRM_CONTACTS.CONTACTS_LANGUAGE, которого нет в SELECT заявление. Как вы можете использовать GROUP BY в подзапросе, где вы возвращаете один столбец.

(SELECT CRM_CONTACTS.ID
    FROM CRM_PRODUCTS_PURCHASE
        LEFT JOIN CRM_CONTACTS ON CRM_PRODUCTS_PURCHASE.CONTACTS_ID = CRM_CONTACTS.ID
        LEFT JOIN CRM_PRODUCTS ON CRM_PRODUCTS_PURCHASE.PRODUCTS_ID = CRM_PRODUCTS.ID
    WHERE CRM_PRODUCTS_PURCHASE.PRODUCTS_ID = 204 AND
        CRM_CONTACTS.CONTACTS_EMAIL!='' AND
        NOT coalesce(CRM_CONTACTS.CONTACTS_DEACTIVATED,0)
        GROUP BY CRM_CONTACTS.CONTACTS_EMAIL
        ORDER BY CRM_CONTACTS.CONTACTS_LANGUAGE)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...