在连接具有不同行postgres的两个表时计数包括0

时间:2017-12-11 12:12:42

标签: sql postgresql postgresql-9.6

我有两个表,users表包含我系统中的所有用户,另一个表叫做action,其中包含我系统中用户完成的所有操作,我想得到的是一个查询,我可以通过用户,如果我没有为一个用户做任何操作,则获得0。

我的两张桌子:

Users Table:

Name       Place
----------------------
James      Supermarket
Alex       Bank 
Ignatius   BookShop

Action table:

Name   Action
--------------------
James  Buy
James  Buy
Alex   Complaint
Alex   Buy
Alex   Buy

我想要这样的事情:

Name       Transactions   Place
-------------------------------
James      2              Supermarket
Alex       3              Bank
Ignatius   0              BookShop

我试过:

SELECT users.name, 
   (SELECT Count(action.name) 
    FROM   action, 
           users 
    WHERE  action.name = users.name 
    GROUP  BY action.name) 
    users.place
FROM 
action, 
users 
WHERE  action.name = users.name 

但总是给我这个错误:

  

错误:用作表达式的子查询返回多行   SQL状态:21000

关于如何做的任何想法?

3 个答案:

答案 0 :(得分:2)

您应首先进行左连接,然后将group by应用于其结果:

SELECT
    u.name
,   COUNT(a.name) AS Transactions
,   u.place
FROM users u
LEFT OUTER JOIN action a ON a.name = u.name 
GROUP BY u.name, u.place

左连接确保即使在action表中没有关联的事务,也不会丢弃用户记录。

答案 1 :(得分:1)

从不FROM子句中使用逗号。始终使用正确的,明确的JOIN语法。也就是说,如果要使用相关子查询,则不需要对此查询进行任何连接:

SELECT u.name, 
       (SELECT Count(*) 
        FROM action a 
        WHERE a.name = u.name 
       ) as cnt,
       u.place
FROM users u;

对于性能,您需要action(name)上的索引。使用此类索引,这可能比使用left joingroup by的其他版本更快。

注意:

  • 所有表都有表别名,这是表名的缩写。
  • 此版本的查询不需要加入。
  • 子查询中没有group by
  • 外部查询中不需要where子句。

答案 2 :(得分:1)

与之前的回答一样,左连接会让你看到。 如果要在结果中包含位置,请在汇总后执行左连接

SELECT a.name,
        ISNULL(b.cnt, 0) AS Transactions,
        a.place
FROM users a
LEFT JOIN
   (SELECT name,
            Count(name) cnt
    FROM   action 
    GROUP  BY name) b
ON a.name =  b.name