【问题标题】:SQL: Bug in Joining two tablesSQL:连接两个表中的错误
【发布时间】:2015-11-23 19:55:31
【问题描述】:

我有一个项目表,我想从中获取项目数量的总和

查询:

Select item_id, Sum(qty) from item_tbl group by item_id

结果:

==================
| ID  | Quantity  |
===================
| 1   | 10        |
| 2   | 20        |
| 3   | 5         |
| 4   | 20        |

第二个表是发票表,我从中获取所售商品的数量。我将这两个表加入为

查询:

Select item_tbl.item_id, Sum(item_tbl.qty) as [item_qty], 
-isnull(Sum(invoice.qty),0) as [invoice_qty] 
from item_tbl 
left join invoice on item_tbl.item_id = invoice invoice.item_id group by item_tbl.item_id

结果:

=================================
| ID  | item_qty  | invoice_qty |
=================================
| 1   | 10        |  -5          |
| 2   | 20        |  -20         |
| 3   | 10        |  -25         |   <------ item_qty raised from 5 to 10 ?? 
| 4   | 20        |  -20         |

我不知道我是否以正确的方式加入这些表格。因为我想从项目表中获取所有内容,并从发票表中获取可用的东西来维护库存。所以我使用左连接。请帮忙..

修改

当我按 item_id 添加分组时,我得到了这个:

=================================
| ID  | item_qty  | invoice_qty |
=================================
| 1   | 10        |  -5          |
| 2   | 20        |  -20         |
| 3   | 5         |  -5          | 
| 3   | 5         |  -20         |
| 4   | 20        |  -20         |

作为一个视图,ID 被重复。我应该怎么做才能避免这种情况??

【问题讨论】:

  • 您是否有可能在其中一个表中有条目 3 的 2 条记录?似乎很奇怪,它只会影响一个项目 ID,所以它一定有一些独特的东西。
  • 如果您有 2 张 id = 3 的发票 - 那么联接将在结果中创建 2 行而不是预期的一行,从而使总和翻倍。您应该通过唯一的结果集进行连接,可能通过使用在您完成连接之前对发票进行分组的子查询。
  • @Ron.B.I 有真正的问题。解决方案非常简单(假设 item_tbl.ID 是唯一的),只需将 item_tbl.qty 添加到您的 group by 子句即可。
  • 我已经回答了,但我想我不太明白
  • @Ron.B.I 你是对的,我必须进行子查询(我以前从未使用过)。你能给我举个例子吗??

标签: sql sql-server join


【解决方案1】:

清理一下,我从 cmets 的回答解释说:

在使用左连接操作(A 左连接 B)时 - 将为每个与 A 记录匹配的 B 记录创建一条记录,此外 - 将为没有匹配 B 记录的任何 A 记录创建一条记录,使用 null需要补充 B 中的字段的值。

我建议在处理此类问题时阅读 SQL 中的 Using Joins

以下是 2 种可能的解决方案,使用不同的假设。


解决方案 A

没有关于主键的任何假设:

我们必须对项目数量列求和才能确定总数量,导致需要执行两个求和,为了可读性和简单性,我建议使用子查询。

select item_tbl.item_id, Sum(item_tbl.qty) as [item_qty], -isnull(Sum(invoice_grouped.qty),0) as [invoice_qty]
from item_tbl left join 
   (select invoice.item_id as item_id, Sum(invoice.qty) as qty from invoice group by item_id) invoice_grouped
on (invoice_grouped.item_id = item_tbl.item_id)
group by item_tbl.item_id


解决方案 B

假设 item_id 是 item_tbl 的主键:

现在我们知道我们可以依赖每个 item_id 只有一个数量这一事实,因此我们可以通过选择连接结果中的任何(最大)项目数量来完成子查询,从而加快执行速度计划。

select item_tbl.item_id, Max(item_tbl.qty) as [item_qty], -isnull(Sum(invoice.qty),0) as [invoice_qty]
from item_tbl left join invoice on (invoice.item_id = item_tbl.item_id)
group by item_tbl.item_id

【讨论】:

    【解决方案2】:

    如果您的数据库设计遵循通用规则,item_tbl.item_id 必须是唯一的。

    所以只需更改您的查询:

    Select item_tbl.item_id, item_tbl.qty as [item_qty], 
    -isnull(Sum(invoice.qty),0) as [invoice_qty] 
    from item_tbl 
    left join invoice on item_tbl.item_id = invoice invoice.item_id group by item_tbl.item_id, item_tbl.qty
    

    【讨论】:

    • 这实际上只有在 item_tbl.qty 是唯一的情况下才有效(我认为这对于 OP 来说是正确的)。
    • 由于id是唯一的,每个id只有一个qty。所以 id+qty 也将是唯一的。
    • 是的,我有点用词不当。由于 OP 提供的可能是真实数据库的一个片段(为了简化问题),ID 不能是唯一的(它可能是外键)。
    • item_id 是 item_tbl 中的 PK,invoice_id 是 inovice 表中的 PK。因此,发票可以有许多具有相同 id 的项目,因为每次找到相同项目 id 时 item_tbl 都会复制一次以上。我猜子查询是最好的,即在加入之前汇总发票。但我不知道如何正确子查询:(
    • @HamzaZaidi 不,问题只是item_id 内部item_tbl 本身并不是独一无二的。既然是你的PK,你不应该有这个答案的问题。
    猜你喜欢
    • 2015-03-03
    • 1970-01-01
    • 1970-01-01
    • 2012-02-28
    • 2012-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多