如何使SQL连接中的原始行消失?

时间:2008-11-16 14:59:16

标签: sql

在此查询中:

SELECT COUNT(*) AS UserCount, Company.* FROM Company
LEFT JOIN User
ON User.CompanyId = Company.Id
WHERE Company.CanAccessSystem= true
AND(User.CanAccessSystem IS null OR User.CanAccessSystem = true)
GROUP BY Company.Id

我想查询可以访问特定系统的公司列表以及可以访问公司内部系统的用户数。

此查询适用于除一个非常重要的情况之外的所有情况。如果公司可以访问系统但没有用户可以访问,则公司完全从查询中消失(即:Users.CanAccessSystem = false)。在这种情况下,我只想要UserCount = 0.

可以访问系统的公司示例:

Users   Company Name
1       WidgetWorks
3       WidgetCompany
0       WidgesRUs

此系统在MySQL上

查询编辑:修复错字“ON User.CompanyId = Company.Id”

5 个答案:

答案 0 :(得分:3)

您的结果不起作用的原因是您没有任何join子句。

SELECT IFNULL(COUNT(User.Id), 0) AS UserCount, Company.* 
FROM Company
LEFT JOIN User ON User.CompanyId = Company.Id AND User.CanAccessSystem = true
WHERE Company.CanAccessSystem = true
GROUP BY Company.Id

那应该有用。左连接的点是主表条目应始终显示,但是左连接条目不必。

IFNULL()仅用于返回0,因为在这种情况下没有合适的用户将呈现NULL值。我不太确定你如何处理MySQL中的布尔值,因为它本身不支持它。

答案 1 :(得分:2)

我想我会从一个生成(不相交)联合的子查询开始:

  • 可以访问至少有一个用户可以访问系统的系统的公司ID和(非零)计数用户
  • 无用户可以访问系统时的公司ID和零计数

假设User.CanAccessSystem IS NULL是考虑LEFT JOIN所需的人工制品,则会导致:

SELECT Company.ID, COUNT(*) AS UserCount
    FROM Company, User
    WHERE Company.ID = User.CompanyID
      AND User.CanAccessSystem = true
UNION
SELECT Company.ID, 0 AS UserCount
    FROM Company
    WHERE NOT EXISTS (SELECT * FROM User
                         WHERE Company.ID = User.CompanyID
                           AND User.CanAccessSystem = true)

您可以使用'AND Company.CanAccessSystem = true'过滤这两个部分,如果大多数公司无法访问系统可能会有所帮助 - 或者您可以将其推迟到最终处理阶段。

然后,您需要将此结果与公司直接连接,确保能够访问系统的公司的过滤条件应用于该行的某个位置。

名义上,这导致以下(未经测试的)代码:

SELECT UserCount, Company.*
    FROM Company JOIN
        (SELECT Company.ID AS ID, COUNT(*) AS UserCount
             FROM Company, User
             WHERE Company.ID = User.CompanyID
               AND User.CanAccessSystem = true
         UNION
         SELECT Company.ID AS ID, 0 AS UserCount
             FROM Company
             WHERE NOT EXISTS (SELECT * FROM User
                                  WHERE Company.ID = User.CompanyID
                                    AND User.CanAccessSystem = true)
        ) AS NumUsers
         ON Company.ID = NumUsers.ID
    WHERE Company.CanAccessSystem = true

答案 2 :(得分:0)

您应该计算User.CanAccessSystem为true的用户数。想想像

这样的东西
 count(case when User.CanAccessSystem then true end)

如果User.CanAccessSystem为false(默认值),case表达式将返回NULL,count(expr)计算表达式不为null的项目数。

所以......这个?

SELECT COUNT(case when User.CanAccessSystem then true end) AS UserCount, Company.*
FROM Company LEFT JOIN User
ON Company.id = user.companyId   -- I had to guess, this seems to be missing in your query
WHERE Company.CanAccessSystem= true
GROUP BY Company.Id

P.S。我使用LEFT JOIN代替INNER JOIN,以便不排除没有用户的公司。

答案 3 :(得分:0)

这里有一个小技巧可以做你想做的事情,利用bool是你可以求和的一个或零(canaccess)来获得可以访问系统的用户数量。为了避免出现NULL问题,COALESCE会将NULL转换为1(即可以访问系统)

mysql> select * from companies;
+------+------------+-----------+
| name | company_id | canaccess |
+------+------------+-----------+
| foo  |          1 |         1 |
| bar  |          2 |         1 |
| baz  |          3 |         1 |
| quux |          4 |         1 |
+------+------------+-----------+
4 rows in set (0.00 sec)

mysql> select * from users;
+---------+------------+-----------+
| user_id | company_id | canaccess |
+---------+------------+-----------+
|       1 |          1 |         1 |
|       2 |          1 |         0 |
|       3 |          1 |         1 |
|       4 |          2 |      NULL |
|       5 |          2 |         1 |
|       6 |          2 |         0 |
|       7 |          3 |         1 |
|       8 |          3 |         0 |
|       9 |          4 |         0 |
+---------+------------+-----------+
9 rows in set (0.00 sec)

mysql> select company_id, sum(canaccess) from 
(select users.user_id, coalesce(users.canaccess,1) as canaccess, 
users.company_id, companies.name from companies join users 
on (users.company_id = companies.company_id) where companies.canaccess = 1 ) foo 
group by company_id;
+------------+----------------+
| company_id | sum(canaccess) |
+------------+----------------+
|          1 |              2 |
|          2 |              2 |
|          3 |              1 |
|          4 |              0 |
+------------+----------------+
4 rows in set (0.00 sec)

答案 4 :(得分:0)

我没有安装MySQL ...在MSSQL上试过这个,我相信,这会处理你的场景,只需稍加修改就可以使MySQL有效......

SELECT c.CompanyID, c.CompanyName, SUM(CASE u.CanAccessSystem WHEN 1 then 1 else 0 end) 
FROM Company c LEFT OUTER JOIN
    [User] u
ON u.CompanyID = c.CompanyID
WHERE c.CanAccessSystem = 1
GROUP BY c.CompanyID, c.CompanyName