Фильтровать второй подзапрос в UNION по результатам первого подзапроса

0

Я пишу запрос, чтобы вытащить контактные данные на основе того, является ли кто-то "высоким донором" или "низким донором", и мой запрос работает отлично, за исключением того, что он будет включать кого-то как highDonor и lowDonor, если они находятся в обе категории, когда мы действительно хотим просто включить их в качестве highDonor.

(Например: Джей Смит пожертвовал 1000 долларов в июне и 50 долларов в июле. Jay будет указан как highDonor, так и lowDonor.)

Чтобы исправить эту проблему, я пытаюсь исключить контакты из lowDonors на основе, если они уже были признаны highDonors. Мой исходный запрос объединил эти подзапросы, но когда я пытаюсь выполнить псевдоним отдельных подзапросов и ссылаться на highDonors во втором подзапросе, я получаю сообщение об ошибке.

(Примечание: это сокращенная версия полного запроса, который фокусируется на частях, которые вызывают ошибку.)

Это ошибка, которую я получаю: #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'highDonors.contactId) as lowDonors ) as highAndLowDonors ' at line 23 #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'highDonors.contactId) as lowDonors ) as highAndLowDonors ' at line 23

SELECT DISTINCT
... 
FROM
    (( 
      SELECT DISTINCT contactid, 
                      "highDonor" AS highorlowdonor 
      FROM            donation 
      WHERE           donationdate > "2015-07-03" 
      AND             donationamount BETWEEN 100 AND 9999.99)
    AS highdonors
UNION ALL 
    ( 
      SELECT DISTINCT contactid, 
                      "lowDonor" AS highorlowdonor 
      FROM            donation 
      WHERE           donationdate > "2015-07-03" 
      AND             donationamount BETWEEN 1 AND 99.99 
      WHERE           contactid NOT IN highdonors.contactid)
    AS lowdonors )
    AS highandlowdonors
    ...

Любые мысли о том, что вызывает здесь ошибку? Могу ли я использовать два подзапроса, подобных этому, и использовать первый внутри второго?

Теги:
union
subquery

2 ответа

3
Лучший ответ

Вы не можете использовать результат из первого запроса во втором, если вы не повторите первый запрос.

Но вы можете переписать запрос в группу contactid и получить максимальное количество donationamount. Положите свою логику в CASE глядя на этот максимум.

SELECT contactid,
       CASE
         WHEN max(donationamount) BETWEEN 100 AND 9999.99
           THEN 'highDonor'
         WHEN max(donationamount) BETWEEN 1 AND 99.99
           THEN 'lowDonor'
       END highorlowdonor
       FROM donation
       WHERE donationdate > '2015-07-03'
       GROUP BY contactid
       HAVING CASE
                WHEN max(donationamount) BETWEEN 100 AND 9999.99
                  THEN 'highDonor'
                WHEN max(donationamount) BETWEEN 1 AND 99.99
                  THEN 'lowDonor'
              END IS NOT NULL;

(Примечание. Без HAVING это будет включать доноров, которые пожертвовали сумму <1 или 99,99 <сумма <100 или сумму> 9999.99, но с highorlowdonor указателя на highorlowdonor. Вместо использования HAVING я бы скорее рекомендовал адаптировать вашу логику к использованию <(или>), а не <= (или> =), который BETWEEN является псевдонимом.)

И BTW: вы используете двойные кавычки ("), где вы должны использовать одинарные кавычки (') (чтобы вложить строки и литералы даты).

  • 0
    Это сработало отлично, хотя я не уверен, где включить предложение HAVING , чтобы исключить нули. Сможете ли вы обновить свой ответ, чтобы включить это? Это было бы очень полезно!
  • 1
    @ StevenRouk: см. Мое редактирование.
1

Вы не можете выровнять два подзапроса, как это, и использовать первый внутри второго. Вы можете попробовать следующее:

    SELECT DISTINCT contactid, 
                      "highDonor" AS highorlowdonor 
      FROM            donation 
      WHERE           donationdate > "2015-07-03" 
      AND             donationamount BETWEEN 100 AND 9999.99)
    AS highdonors
UNION ALL 

      SELECT DISTINCT contactid, 
                      "lowDonor" AS highorlowdonor 
      FROM            donation 
      WHERE           donationdate > "2015-07-03" 
      AND             donationamount BETWEEN 1 AND 99.99 
      AND           contactid NOT IN (select contact_id
FROM            donation 
      WHERE           donationdate > "2015-07-03" 
      AND             donationamount BETWEEN 100 AND 9999.99)

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню