【问题标题】:Stuck on mysql nested select statement卡在mysql嵌套选择语句上
【发布时间】:2019-02-04 01:08:21
【问题描述】:

我在一个选择语句中加入了三个表:

表 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=monthly_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)

【问题讨论】:

  • 你的查询中是NOT coalesce吗?
  • 让我们在您的表格中获取一些示例数据以供我们查看以及预期的输出。
  • 不合并我使用,因为我的数据库中的 contacts_deactivated 可以是 0 或 Null

标签: mysql sql


【解决方案1】:

您应该尽可能避免嵌套子选择,因为它们很难让 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 - order by inside subquery

在我们的实际案例中,我们经常发现将上述内容作为 2 个查询运行要好几个数量级。即生成一个 CONTACTS_ID 列表并将值存储在 PHP 变量中,然后在 NOT IN 子句中使用这些值进行第二次查询。

【讨论】:

    【解决方案2】:

    首先你提到了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)
    

    【讨论】:

    • 我没有提到 CONTACTS_LANGUAGE 因为它对输出没有真正的重要性。 group_by 是必要的,因为多个联系人可以拥有相同的电子邮件地址,而我只想向他们发送一次电子邮件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-15
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多