根据第一个子查询的结果过滤UNION中的第二个子查询

时间:2018-07-04 01:28:27

标签: mysql sql subquery union

我正在编写一个查询,以根据某人是“高捐助者”还是“低捐助者”来提取联系人数据,并且我的查询工作得很好,除了它会同时包括highDonor和lowDonor的人在这两个类别中,当我们真的只想将它们作为highDonor纳入时。

(例如:杰伊·史密斯在6月和7月分别捐赠了1000美元和50美元。周杰伦将同时被列为highDonor和lowDonor。)

为解决此问题,我正在尝试根据是否已被发现为highDonors来将其排除为lowDonors。我原来的查询合并了这些子查询,但是当我尝试为单个子查询加上别名并在第二个子查询中引用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

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
    ...

对导致此错误的原因有何想法?我可以这样对两个子查询进行别名并在第二个子查询中使用第一个吗?

2 个答案:

答案 0 :(得分: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为空的捐赠者。 {1}}我建议您修改您的逻辑以使用<(或>)而不是<=(或> =),其中HAVING是它的别名。)

和顺便说一句:您正在使用双引号(BETWEEN),而应使用单引号(")(以括起字符串和日期文字)。

答案 1 :(得分: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)

一种更有效的方法是将第一个联合选择存储在临时表中,并在联合中使用,然后在第二个联合选择查询中使用相同的临时表来排除高施主。