MySQL - извлечение максимального значения связанного столбца в левом соединении с периметром, отличным от предложения WHERE основного запроса. - PullRequest
1 голос
/ 26 сентября 2019

Я использую 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, следовательно, LEFT JOIN, который я использую.

  • Вы можете видеть, что author по типу продублирован, поскольку он и в первой, и во второй таблице каждый раз связан с query_result_id.Важно отметить.

  • email_nb - это целое число от 0 до 10

  • , есть предложение LIMIT, так как мне нужнополучить определенное количество записей

Сегодня мой запрос направлен на получение query_results с определенным количеством условий на Специфика состоит в том, что я обязательно получаю query_results с author, которыйне появляется ни в одном customer_email_id, где days_since_sending будет менее 60 дней: это означает, что я проверяю эти days_since_sending не только в записях для этого запроса, но и во всех customers_emails спасибов подзапрос NOT IN (см. ниже).

Это мой текущий запрос для customer_id = 12 и query_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         |   
+-----------------------------+------------+--------------+

Мой вызов / сложность сегодня:

  • Уведомление на 2-й строке Эрик привязан к email_nb 2 ине максимум всех электронных писем Эрика, которые могли бы быть 4, если бы мы взяли максимум email_nb для ВСЕХ сообщений до author=eric.но мы остаемся в пределах customer_id = 12, поэтому остается только один с email_nb = 2

  • Также обратите внимание, что в первой строке email_nb, связанный с query_result = 10, равен7, а не 3, что могло бы иметь место, поскольку 3 - это то, что указано в таблице customers_emails в последней строке.

  • Действительно для писем на адрес 'Джон, у меня был выбор между email_nb 2, 7 и 3, но я выбираю самое высокое, так что это 7 (даже если это письмо было получено более 60 дней назад !! Это очень важно и частичноиз того, что я не знаю, как сделать: периметры разные: сегодня я получаю все query_results, где author НЕ было отправлено электронное письмо в течение последних 60 дней (см. подзапрос NOT IN), НО мне нужноукажите в столбце максимум email_nb, отправленный на john на customer_id=12 и query_id=1 ДАЖЕ, если он был отправлен более 60 дней назад, так что это разные периметры ... Не знаю, как это сделать...

  • Другими словами, я не хочу найти максимальный (email_nb) wiСмажьте те же самые пункты WHERE, как days_since_sending >= 60 или в пределах того же LIMIT и GROUP BY ..., что и мой текущий запрос: мне нужно получить максимальное значение email_nb для customer_id=12 AND query_id=1 иотправлено на john по ВСЕМ записям в таблице customers_emails!

  • Если вообще нет связанной строки в customer_emails (это означает, что электронное письмо не былокогда-либо отправленный этим клиентом для этого запроса в прошлом), тогда email_nb должен быть чем-то вроде NULL ..

Это означает, что я НЕ хочу этого вывода:

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

Как этого добиться в MySQL 5.6?

Ответы [ 2 ]

0 голосов
/ 26 сентября 2019

Так как вы немного запутались, я подошел к этому.

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;
0 голосов
/ 26 сентября 2019

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

Первое, что вы хотите сделать, это:

Специфика заключается в том, что я обязательно получаю query_results с автором, который не указан ни в одном из customer_email_id, где days_since_sending будет меньше 60 дней

Это может выглядеть примерно так:

-- 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 дней, которое появляется для данного идентификатора запроса.Ваше следующее требование:

Мне нужно, чтобы в столбце был указан максимальный размер email_nb, отправленного Джону 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

Получает максимальный email_nb для каждой комбинации author / query_result, без учета даты вообще.

Единственное, что осталось сделать, - это сократить набор результатов от второго запроса до тех авторов, которые появляются в первом запросе.Есть несколько разных способов сделать это.Например, вы можете ВНУТРИ СОЕДИНИТЬ эти два запроса с помощью 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

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

...