如何在单个mysql查询中获得相同的结果

时间:2016-03-09 11:07:23

标签: mysql

现在我使用两个查询来计算某次点击的联系人数量。 我尝试了很多东西,比如 left join right join union ,但我可以检索预期的结果。

第一个查询

SELECT offertId, count(*) as returnClicks from warehause where userId=8

返回

| offertId | returnClicks |
|    47    |      4       |

而第二

SELECT offertId, count(*) as returnContacts from contact where userId=8

返回

| offertId | returnContacts |
|    47    |        1       |

如何进行单一查询才能获得此类结果?

| offertId | returnClicks | returnContacts |
|    47    |      4       |        1       |

别担心,如果我没有返回点击,我当然不需要计算联系人。

6 个答案:

答案 0 :(得分:3)

首先要做的事情是:您的查询可能是 1 无效的SQL,因为offertId子句中未显示聚合的SELECT列未显示在{{1子句。从版本5.7.5开始,MySQL拒绝 2 这样的查询。以前的版本会处理它们,但它们可以GROUP BYoffertId条件选择的列offertId中以WHERE的形式自由返回。

您确定在两个查询中都不想GROUP BY offertId吗?

我会假设您的查询都包含GROUP BY offertId以获得正确的结果。

1 查询有效并返回预期结果当且仅当 offertId在功能上依赖于userId;即userId中具有特定值的所有行也共享列offertId的值。

2 从版本5.7.5开始,使用默认配置,MySQL拒绝queries that use GROUP BY incorrectly。以前版本的MySQL用于接受此类查询,但它们为未出现在GROUP BY子句中且未与GROUP BY aggregate functions一起使用的列返回的值是不确定的。
要让现有代码运行,可以关闭MySQL 5.7.7引入的设置。如果您没有在服务器上运行旧查询,建议不要将其关闭;您最好在新代码中编写有效的SQL查询,而不是依赖于实现细节(无论如何都会产生不确定的结果)。

原始解决方案,鉴于查询已更改为包含GROUP BY

您可以JOIN您已经拥有的两个查询返回的结果:

SELECT *
FROM (
    SELECT offertId, count(*) as returnClicks from warehause where userId=8 GROUP BY offertId
) clicks
LEFT JOIN (
    SELECT offertId, count(*) as returnContacts from contact where userId=8 GROUP BY offertId
) contacts USING (offertId)

它将返回第一个子查询生成的所有行以及第二个子查询生成的结果集中的匹配行。

我假设第一个子查询在offertId中返回第二个子查询在offertId中返回的所有值。如果他们采取相反的方式,那么只需将LEFT JOIN替换为RIGHT JOIN

备注:如果两个子查询返回的offertId值集合未包含在另一个中,则上述查询不会返回你需要的所有结果。在这种情况下,您需要使用FULL OUTER JOIN(它包括来自双方的所有行)但不幸的是,MySQL不支持它。

否 - GROUP BY解决方案

操作提到他们不需要使用GROUP BY。在这种情况下,每个原始查询最多返回一行。如果子查询在offertId中返回的值匹配,则上面提供的代码也可以生效并返回包含offertIdreturnClicksreturnContacts的一行。如果它们不匹配(或其中一个不返回任何行),则最终结果集将错过第二个子查询生成的值。

获取结果集中所有值的可能解决方案是更改结果集的格式。

此查询:

SELECT 'clicks' as kind, offertId, count(*) as number from warehause where userId=8
UNION
SELECT 'contacts' as kind, offertId, count(*) as number from contact where userId=8

生成此结果集:

| kind     | offertId | number |
| clicks   |    47    |    4   |
| contacts |    47    |    1   |

它包含两个查询返回的所有行,无论它们返回0行还是1行,无论offertId的值是否匹配。

kind告诉哪个子查询生成了行,number列告诉COUNT(*)从相应的子查询中生成的值。

可以在客户端代码中以任何方式分析,组合和处理这些值(假设它不是存储过程,并且在客户端使用了更强大的语言)。

答案 1 :(得分:2)

使用相关查询,这对所有用户都是动态的。

SELECT t.offerTID,count(*) as returnClicks,
       (SELECT count(*) FROM returnContacts s
        WHERE t.userID = s.userID) as returnContacts
FROM returnClicks t

您可以在末尾添加where子句以过滤所需的用户

如果每个用户都有多个offerTID,那么你应该添加一个group by子句:

SELECT t.offerTID,count(*) as returnClicks,
       (SELECT count(*) FROM returnContacts s
        WHERE t.userID = s.userID AND t.offerID = s.offerID) as returnContacts
FROM returnClicks t
GROUP BY t.offerTID

答案 2 :(得分:1)

试试这个:

SELECT COALESCE(t1.offertId, t2.offertId) AS offertId,
        returnClicks, returnContacts
FROM (SELECT offertId, count(*) AS returnClicks 
      FROM warehause 
      WHERE userId=8
) AS t1
CROSS JOIN (
  SELECT offertId, count(*) AS returnContacts 
  FROM contact 
  WHERE userId=8) AS t2

两个查询都返回始终一行,因此您可以使用CROSS JOIN绑定它们。

Demo here

答案 3 :(得分:0)

将2个查询作为子查询与连接组合:

select t1.offertId, t1.returnClicks, t2.returnContacts 
from 
    (SELECT offertId, count(*) as returnClicks 
     from warehause 
     where userId=8) AS t1
inner join
    (SELECT offertId, count(*) as returnContacts 
     from contact where userId=8) AS t2

答案 4 :(得分:0)

像这样:

SELECT *
FROM       (SELECT 1 as tmpId, offertId, count(*) as returnClicks from warehause where userId=8) t1
INNER JOIN (SELECT 1 as tmpId, offertId, count(*) as returnContacts from contact where userId=8) t2 on t1.tmpId = t2.tmpId

如果联接的一侧或两侧可能没有返回任何行,您可能希望将上面的查询更改为外部联接。

PS:从我的手机上发布,所以它可能有一些小错误,因为我无法测试它。

答案 5 :(得分:0)

选择a.offertId,将(a.offertId)计数为returnContacts,将count(b.offertId)作为returnClick来自联系人a.userid = b.userid中的join warehause b,其中userId = 8