SQL Server COUNT多个表返回错误结果
以下是表格: 来自acc账户SQL Server COUNT多个表返回错误结果,sql,sql-server,Sql,Sql Server,以下是表格: 来自acc账户 AccountName ------------- Account #1 Account #3 Account #2 来自部门,作为与客户合并的部门 AccountName DivisionName ----------- --------------------------- Account #1 Division TWO for Account #1 Account #1 Division ONE for Account #1 来自AccountSupp
AccountName
-------------
Account #1
Account #3
Account #2
来自部门,作为与客户合并的部门
AccountName DivisionName
----------- ---------------------------
Account #1 Division TWO for Account #1
Account #1 Division ONE for Account #1
来自AccountSuppliers作为acc_sup(多对多加入)
以下是查询:
SELECT
acc.AccountName,
COUNT(div.AccountId) AS CountDivisions,
COUNT(acc_sup.AccountId) AS CountSuppliers
FROM
Account AS acc
LEFT JOIN
Division AS div ON (div.AccountId = acc.Id)
LEFT JOIN
AccountSupplier AS acc_sup ON (acc_sup.AccountId = acc.Id)
GROUP BY
acc.AccountName
结果如下:
AccountName CountDivisions CountSuppliers
----------- --------------- --------------
Account #1 6 6
Account #2 0 2
Account #3 0 0
应该是:
AccountName CountDivisions CountSuppliers
----------- --------------- --------------
Account #1 2 3
Account #2 0 2
Account #3 0 0
请注意,添加DISTINCT关键字也会产生奇怪的结果:
SELECT
acc.AccountName,
COUNT(DISTINCT div.AccountId) AS CountDivisions,
COUNT(DISTINCT acc_sup.AccountId) AS CountSuppliers
FROM
Account AS acc
LEFT JOIN
Division AS div ON (div.AccountId = acc.Id)
LEFT JOIN
AccountSupplier AS acc_sup ON (acc_sup.AccountId = acc.Id)
GROUP BY
acc.AccountName
产生:
AccountName CountDivisions CountSuppliers
----------- --------------- --------------
Account #1 1 1
Account #2 0 1
Account #3 0 0
嗯?我可能忽略了一些简单的东西,但这个结果显然是不正确的。有人能为我推荐一种正确的方法来编写这个查询以获得正确的结果吗
谢谢 只需在要计算唯一值的位置添加
DISTINCT
:
SELECT acc.AccountName,
COUNT(DISTINCT div.AccountId) AS CountDivisions,
COUNT(DISTINCT acc_sup.AccountId) AS CountSuppliers
FROM Account AS acc
LEFT JOIN Division AS div ON (div.AccountId = acc.Id)
LEFT JOIN AccountSupplier AS acc_sup ON (acc_sup.AccountId = acc.Id)
GROUP BY acc.AccountName, div.AccountId, acc_sup.AccountId
您可以在count statemetns中使用distinct关键字
SELECT acc.AccountName,
COUNT(distinct div.AccountId) AS CountDivisions,
COUNT(distinct acc_sup.AccountId) AS CountSuppliers
FROM Account AS acc
LEFT JOIN Division AS div ON (div.AccountId = acc.Id)
LEFT JOIN AccountSupplier AS acc_sup ON (acc_sup.AccountId = acc.Id)
GROUP BY acc.AccountName
或更节省资源的方式:
SELECT
acc.AccountName,
(SELECT COUNT(*) FROM Division where div.AccountId = acc.Id) CountDivisions,
(SELECT COUNT(*) FROM AccountSupplier WHERE acc_sup.AccountId = acc.Id) AS CountSuppliers
FROM aCCOUNT AS acc
查询中导致错误结果的问题是您要求计算错误的字段
SELECT
acc.AccountName,
COUNT(div.AccountId) AS CountDivisions,
COUNT(acc_sup.AccountId) AS CountSuppliers
FROM
Account AS acc
LEFT JOIN
Division AS div ON (div.AccountId = acc.Id)
LEFT JOIN
AccountSupplier AS acc_sup ON (acc_sup.AccountId = acc.Id)
GROUP BY
acc.AccountName
当count更改为CountDivisions时,-div.AccountId
是联接中使用的字段,因此组中的每一行的值都是相同的-计算这些不同的值时,无论有多少个匹配的值,当然都是1
计数应该在子表中的唯一字段上,假设您有一个ID
字段,则其如下所示:
SELECT
acc.AccountName,
COUNT(DISTINCT div.Id) AS CountDivisions,
COUNT(DISTINCT acc_sup.Id) AS CountSuppliers
FROM
Account AS acc
LEFT JOIN
Division AS div ON (div.AccountId = acc.Id)
LEFT JOIN
AccountSupplier AS acc_sup ON (acc_sup.AccountId = acc.Id)
GROUP BY
acc.AccountName
你很接近。您只是错过了计算聚合所需的列 根据您的设置数据,让我们看一下将要处理的给定查询中的数据。我们希望使用
左外部联接
s,因为我们希望计算所有帐户名
s,即使没有任何部门名
s或供应商名
s。对于那些,我们将得到null
,这将转换为0
计数
因此:
给了我们:
这为我们提供了我们所期望的计数:
AccountName | CountDivisions | CountSuppliers
:---------- | -------------: | -------------:
会计科目1 | 2 | 3
Acct2 | 0 | 2
Acct3 | 0 | 0
dbfiddle提示:
DISTINCT
insideCOUNT()
会有帮助。@yogesharma-否。我尝试将DISTINCT添加到计数聚合中。我得到一个不同的结果集,但它也是错误的。请添加您的数据。Simonare--您的第一个建议也会产生一个奇怪的结果集。我按问题编辑以显示这一点。然而,你的第二个建议非常有效。这是首选的解决方案。谢谢@CCPony:这个答案也显示了问题所在,COUNT(distinct div.AccountId)
vsdiv.AccountId=acc.Id
在子查询的where子句中-您计算的是帐户Id,而不是唯一标识行的标识值-这就是为什么添加distinct关键字会产生值1的原因,我没有按提交按钮。根据您使用的数据和索引(以及您的SQL Server版本),基于纯JOIN
withDISTINCT
或使用Simonare的相关子查询示例,您可能会获得不同的性能。你会想测试的。
SELECT
acc.AccountName,
COUNT(DISTINCT div.Id) AS CountDivisions,
COUNT(DISTINCT acc_sup.Id) AS CountSuppliers
FROM
Account AS acc
LEFT JOIN
Division AS div ON (div.AccountId = acc.Id)
LEFT JOIN
AccountSupplier AS acc_sup ON (acc_sup.AccountId = acc.Id)
GROUP BY
acc.AccountName
SELECT *
FROM Account acc
LEFT JOIN Division div ON (div.AccountId = acc.Id)
LEFT JOIN AccountSupplier acc_sup ON (acc_sup.AccountId = acc.Id) ;
id | AccountName | accountID | DivisionName | accountID | SupplierName
-: | :---------- | --------: | :----------- | --------: | :-----------
1 | Acct1 | 1 | Div2 | 1 | Supplier6
1 | Acct1 | 1 | Div2 | 1 | Supplier1
1 | Acct1 | 1 | Div2 | 1 | Supplier3
1 | Acct1 | 1 | Div1 | 1 | Supplier6
1 | Acct1 | 1 | Div1 | 1 | Supplier1
1 | Acct1 | 1 | Div1 | 1 | Supplier3
2 | Acct2 | null | null | 2 | Supplier1
2 | Acct2 | null | null | 2 | Supplier2
3 | Acct3 | null | null | null | null
SELECT
acc.AccountName,
COUNT(DISTINCT div.DivisionName) AS CountDivisions,
COUNT(DISTINCT acc_sup.SupplierName) AS CountSuppliers
FROM Account acc
LEFT JOIN Division div ON div.AccountId = acc.Id
LEFT JOIN AccountSupplier acc_sup ON acc_sup.AccountId = acc.Id
GROUP BY acc.AccountName ;
AccountName | CountDivisions | CountSuppliers
:---------- | -------------: | -------------:
Acct1 | 2 | 3
Acct2 | 0 | 2
Acct3 | 0 | 0