MySQL - 检索 LEFT JOIN 中关联列的最大值,其周长与主查询的 WHERE 子句不同



我正在使用MySql 5.6并且有一个带有 LEFT JOIN 的选择查询,但我需要检索关联列的最大值email_nb),但约束的"周长"不同。

让我们举个例子:让我声明它只是一个只有 5 行的示例,但当我有数千行时它也应该有效......(我之所以这么说,是因为我的查询中有一个LIMIT子句)

表 'query_results'

+-----------------------------+------------+--------------+
| query_result_id             | query_id   | author       |
+-----------------------------+------------+--------------+
| 2                           |         1  | john         |
| 3                           |         1  | eric         |
| 7                           |         3  | martha       |
| 9                           |         4  | john         |
| 10                          |         1  | john         |
+-----------------------------+------------+--------------+

表 'customers_emails'

+-------------------+-----------------+--------------+-----------+-------------+------------------------
| customer_email_id | query_result_id | customer_id  | author    |  email_nb   | days_since_sending
+-------------------+-----------------+--------------+-----------+-------------+------------------------
| 5                 |         2       | 12           |  john     |   2         |  150
| 12                |         3       | 7            |  eric     |   4         |  90
| 27                |         3       | 12           |  eric     |   2         |  86
| 40                |         9       | 15           |  john     |   9         |  87
| 42                |         2       | 12           |  john     |   7         |  23
| 51                |         10      | 12           |  john     |   3         |  89
+-------------------+-----------------+--------------+-----------+-------------+-----------------------

笔记:

  • 你可以有一个query_result,作者在任何customers_emails中都出现在 NO 行中,因此我正在使用LEFT JOIN

  • 您可以看到author设计上是重复的,因为它每次都与query_result_id相关联时在第一个表和第二个表上。需要注意的是。

  • email_nb是介于 0 和 10 之间的整数

  • 有一个LIMIT子句,因为我需要检索一定数量的记录

今天我的查询旨在检索具有一定数量条件的query_results具体之处在于,我确保检索query_results与未出现在days_since_sending少于 60 天的任何customer_email_idauthor: 这意味着我不仅在此查询的记录中检查这些days_since_sending, 但是由于子查询NOT IN,在所有customers_emails中(见下文)。

这是我目前对customer_id = 12query_id = 1的查询

SELECT             
qr.query_result_id,     
qr.author,
FROM
query_results qr
LEFT JOIN
customers_emails ce
ON
qr.author = ce.author           
WHERE
qr.query_id = 1 AND
qr.author IS NOT NULL            
AND qr.author NOT IN (
SELECT recipient
FROM customers_emails
WHERE               
(
customer_id = 12 AND
( days_since_sending >= 60) ) 
)           
)     
# we don't take by coincidence/bad luck 2 query results with the same author
GROUP BY
qr.author
ORDER BY 
qr.query_result_id ASC
LIMIT 
20

这是预期的输出:

+-----------------------------+------------+--------------+
| query_result_id             | author     | email_nb     |  
+-----------------------------+------------+--------------+
|        10                   |   john     |    7         |
|        3                    |   eric     |    2         |   
+-----------------------------+------------+--------------+

我今天的挑战/困难:

  • 请注意,在第二行,Eric 与email_nb2相关联,而不是 Eric 所有电子邮件中的最大值,如果我们将所有邮件的最大email_nb个发送到author=eric,则可以4这些电子邮件。 但我们保持在customer_id = 12的限制范围内,所以只剩下一个email_nb = 2

  • 另请注意,在第一行,与query_result = 10关联的email_nb7,而不是3,这可能是这种情况,因为3是最后一行表customers_emails中显示的内容。

  • 事实上,对于发送给"约翰"的电子邮件,我可以在email_nb273之间进行选择,但我拿得最高,所以它7(即使这封电子邮件来自 60 多天前!!这非常重要,也是我不知道该怎么做的一部分:周界不同:今天我检索过去 60 天未向author发送电子邮件的所有query_results(请参阅NOT IN子查询)但我需要在列中包含customer_id=12发送给john的最大email_nb,即使发送超过 60query_id=1几天前,所以这些是不同的周边...真的不知道该怎么做...

  • 换句话说,这意味着我不想在相同的WHERE子句中找到最大值(email_nb),例如days_since_sending >= 60或相同的限制和分组依据...作为我当前的查询:我需要的是检索customer_id=12query_id=1email_nb最大值,并发送到customers_emails表上所有记录john

  • 如果customers_emails上根本没有关联的行(这意味着该客户过去从未为此查询发送电子邮件),则email_nb应该像 NULL 一样

这意味着我不想要这个输出:

+-----------------------------+------------+--------------+
| query_result_id             | author     | email_nb     |  
+-----------------------------+------------+--------------+
|        10                   |   john     |    3         |
|        3                    |   eric     |    2         |   
+-----------------------------+------------+--------------+

如何在MySQL 5.6中实现这一点?

由于您有点困惑,因此我想到了这个。

select 
max(q.query_result_id) as query_result_id,q.author,max(email_nb) as email_nb
from query_results q
left join customers_emails c on q.author=c.author
where customer_id=12 and query_id=1
group by q.author;

我认为在这种情况下最好的办法是将其分解为较小的查询,然后将它们组合在一起。

您要做的第一件事是:

具体之处在于,我确保与未出现在days_since_sending少于60天的任何customer_email_id的作者一起检索query_results

这可能看起来像这样:

-- Query A
SELECT DISTINCT q.author FROM query_results q
WHERE q.author NOT IN (
SELECT c.author FROM customers_emails c
WHERE c.days_since_sending < 60
)
AND q.query_id = 1

这将为你提供在过去 60 天内没有针对给定查询 ID 显示的电子邮件的作者列表(已删除重复项)。您的下一个要求如下:

我需要在列中email_nb发送给 john 的最大customer_id=12 和 query_id=1,即使它是在 60 多天前发送

此查询可能如下所示:

-- Query B
SELECT c.query_result_id, c.author, MAX(c.email_nb) as max_email_nb
FROM customers_emails c
LEFT JOIN query_results q ON c.author = q.author
WHERE c.customer_id = 12
AND q.query_id = 1
GROUP BY c.query_result_id, c.author

这样可以获得每个作者/query_result组合的最大email_nb,根本不考虑日期。

剩下要做的就是将第二个查询的结果集减少到仅出现在第一个查询中的作者。有几种不同的方法可以做到这一点。例如,您可以通过author来内部联接两个查询:

SELECT b.* FROM (
-- Query B
SELECT c.query_result_id, c.author, MAX(c.email_nb) as max_email_nb
FROM customers_emails c
LEFT JOIN query_results q ON c.author = q.author
WHERE c.customer_id = 12
AND q.query_id = 1
GROUP BY c.query_result_id, c.author
) b INNER JOIN (
-- Query A
SELECT DISTINCT q.author FROM query_results q
WHERE q.author NOT IN (
SELECT c.author FROM customers_emails c
WHERE c.days_since_sending < 60
)
AND q.query_id = 1
) a ON a.author = b.author

您可以使用另一个 NOT IN 子句:

SELECT b.* FROM (
-- Query B
SELECT c.query_result_id, c.author, MAX(c.email_nb) as max_email_nb
FROM customers_emails c
LEFT JOIN query_results q ON c.author = q.author
WHERE c.customer_id = 12
AND q.query_id = 1
GROUP BY c.query_result_id, c.author
) b
WHERE b.author NOT IN (
-- Query A
SELECT DISTINCT q.author FROM query_results q
WHERE q.author NOT IN (
SELECT c.author FROM customers_emails c
WHERE c.days_since_sending < 60
)
AND q.query_id = 1
) a

最有可能的方法可以提高此查询的速度或减少代码行数,但是如果需要这样做,您现在至少可以与结果进行比较的查询。

最新更新