LEFT JOIN 产生夸大的 COUNT() 数字

Bel*_*igh 4 sql-server t-sql sql-server-2008-r2

我有 3 张表正在使用Right Join。数据设置如下 - 我的问题是返回的数字不准确,因此当我执行查询时,我得到了返回(这是准确值的两倍和三倍)

vendor     TotalSales   TotalCases
Vendor 1    61.40          6
Run Code Online (Sandbox Code Playgroud)

但如果你手动计算它应该是

vendor     TotalSales   TotalCases
Vendor 1    30.70          2
Run Code Online (Sandbox Code Playgroud)

我必须在查询中更改哪些内容才能返回上述结果?

  Declare @BBC Table
  (
    vendor varchar(250)
    ,vendorcasenum varchar(100)
    ,casenumdate date
  )

  Declare @AllVendor Table
  (
    vendor varchar(250)
  )

  Declare @TotalSalesAmt Table
  (
    vendor varchar(250)
    ,saleamt decimal(10,2)
  )

  Insert Into @TotalSalesAmt (vendor, saleamt) VALUES
  ('Vendor 1', '10.20'), ('Vendor 2', '10.10'), ('Vendor 1', '.40')
  ,('Vendor 1', '20.10'), ('Vendor 2', '20.10'), ('Vendor 3', '20.00')

  Insert Into @AllVendor (vendor) Values
  ('Vendor 1'), ('Vendor 2'), ('Vendor 3'), ('Vendor 4')
  ,('Vendor 5'), ('Vendor 6'), ('Vendor 7'), ('Vendor 8')
  ,('Vendor 9'), ('Vendor 10'), ('Vendor 11'), ('Vendor 12')
  ,('Vendor 13'), ('Vendor 14'), ('Vendor 15'), ('Vendor 16')
  ,('Vendor 17'), ('Vendor 18'), ('Vendor 19'), ('Vendor 20')

 Insert Into @BBC (vendor, vendorcasenum, casenumdate) VALUES
('Vendor 11',   'A12344',    '2017-01-19')
,('Vendor 10',  'A12311',    '2014-05-12')
,('Vendor 9',   'A12889',    '2015-07-10')
,('Vendor 8',   'A12988',    '2016-07-01')
,('Vendor 7',   'A12931',    '2012-03-07')
,('Vendor 6',   'A12199',    '2011-10-05')
,('Vendor 5',   'E12331',    '2011-10-11')
,('Vendor 4',   'E12391',    '2014-12-16')
,('Vendor 3',   'E12300',    '2011-07-15')
,('Vendor 2',   'E11001',    '2011-06-15')
,('Vendor 1',   'E12301',    '2013-11-06')
,('Vendor 1',   'E12221',    '2013-11-06')

Select
av.vendor
,TotalSales = SUM(ISNULL(tsa.saleamt,0))
,TotalCases = COUNT(bbc.vendorcasenum)
FROM @AllVendor av
LEFT JOIN @BBC bbc
ON av.vendor = bbc.vendor
LEFT JOIN @TotalSalesAmt tsa
ON tsa.vendor = av.vendor
GROUP BY av.vendor
ORDER BY av.vendor ASC
Run Code Online (Sandbox Code Playgroud)

编辑
我也尝试使用 aCTE来实现我想要的结果,但得到了同样不正确的结果:

WITH tsa As
(
    Select 
    vendor
    ,saleamt
    FROM @TotalSalesAmt
)
,BBC As
(
    Select 
    vendor
    ,vendorcasenum
    FROM @BBC
)
Select 
av.vendor
,TotalSales = ISNULL(SUM(tsa.saleamt),0)
,TotalCases = COUNT(bbc.vendorcasenum)
FROM @AllVendor av
LEFT JOIN TSA tsa
ON tsa.vendor = av.vendor
LEFT JOIN BBC bbc
ON bbc.vendor = av.vendor
GROUP BY av.vendor
ORDER BY av.vendor
Run Code Online (Sandbox Code Playgroud)

McN*_*ets 9

如果您在没有聚合的情况下运行查询,您将看到正在发生的事情:

Select
    *
FROM @AllVendor av
    LEFT JOIN @BBC bbc
        ON av.vendor = bbc.vendor
    LEFT JOIN @TotalSalesAmt tsa
        ON tsa.vendor = av.vendor
where av.vendor = 'vendor 1'

+----------+----------+---------------+---------------------+----------+---------+
| vendor   |  vendor  | vendorcasenum |     casenumdate     |   vendor | saleamt |
+----------+----------+---------------+---------------------+----------+---------+
| Vendor 1 | Vendor 1 | E12301        | 06.11.2013 00:00:00 | Vendor 1 | 10,20   |
| Vendor 1 | Vendor 1 | E12301        | 06.11.2013 00:00:00 | Vendor 1 | 0,40    |
| Vendor 1 | Vendor 1 | E12301        | 06.11.2013 00:00:00 | Vendor 1 | 20,10   |
| Vendor 1 | Vendor 1 | E12221        | 06.11.2013 00:00:00 | Vendor 1 | 10,20   |
| Vendor 1 | Vendor 1 | E12221        | 06.11.2013 00:00:00 | Vendor 1 | 0,40    |
| Vendor 1 | Vendor 1 | E12221        | 06.11.2013 00:00:00 | Vendor 1 | 20,10   |
+----------+----------+---------------+---------------------+----------+---------+
Run Code Online (Sandbox Code Playgroud)

由于@BBC 表中有 2 行Vendor 1

('Vendor 1',   'E12301',    '2013-11-06')
('Vendor 1',   'E12221',    '2013-11-06')
Run Code Online (Sandbox Code Playgroud)

聚合的 SUM(saleamt) = 61.40

您可以使用一个子查询来计算SUM(saleamt),另一个来计算COUNT(vendorcasenum)

Select
    vendor,
    (select ISNULL(SUM(tsa.saleamt),0)
     from @TotalSalesAmt tsa
     where tsa.vendor = av.vendor) TotalSales,
    (select COUNT(bbc.vendorcasenum)
     from @BBC bbc
     where av.vendor = bbc.vendor) TotalCases
FROM @AllVendor av
ORDER BY av.vendor ASC;
Run Code Online (Sandbox Code Playgroud)

这是最终结果:

+-----------+------------+------------+
|   vendor  | TotalSales | TotalCases |
+-----------+------------+------------+
| Vendor 1  | 30,70      | 2          |
| Vendor 10 | 0,00       | 1          |
| Vendor 11 | 0,00       | 1          |
| Vendor 12 | 0,00       | 0          |
| Vendor 13 | 0,00       | 0          |
| Vendor 14 | 0,00       | 0          |
| Vendor 15 | 0,00       | 0          |
| Vendor 16 | 0,00       | 0          |
| Vendor 17 | 0,00       | 0          |
| Vendor 18 | 0,00       | 0          |
| Vendor 19 | 0,00       | 0          |
| Vendor 2  | 30,20      | 1          |
| Vendor 20 | 0,00       | 0          |
| Vendor 3  | 20,00      | 1          |
| Vendor 4  | 0,00       | 1          |
| Vendor 5  | 0,00       | 1          |
| Vendor 6  | 0,00       | 1          |
| Vendor 7  | 0,00       | 1          |
| Vendor 8  | 0,00       | 1          |
| Vendor 9  | 0,00       | 1          |
+-----------+------------+------------+
Run Code Online (Sandbox Code Playgroud)


ype*_*eᵀᴹ 6

还有另一种方法,没有内联子查询,你GROUP BY先加入,然后加入,有 3 种风格:

  • 派生表
  • CTE
  • OUTER APPLY

使用 CTE:

WITH 
  tsa AS
  (
    SELECT
        vendor
        TotalSales = SUM(saleamt)
    FROM @TotalSalesAmt
    GROUP BY vendor
  ),
  bbc AS
  (
    SELECT  
        vendor,
        TotalCases = COUNT(vendorcasenum)
    FROM @BBC
    GROUP BY vendor
  )
SELECT 
    av.vendor,
    TotalSales = COALESCE(tsa.TotalSales, 0),
    TotalCases = COALESCE(bbc.TotalCases, 0)
FROM 
    @AllVendor AS av
  LEFT JOIN tsa
    ON tsa.vendor = av.vendor
  LEFT JOIN bbc
    ON bbc.vendor = av.vendor
ORDER BY
    av.vendor ;
Run Code Online (Sandbox Code Playgroud)