为什么这个查询会使结果加倍?

时间:2011-09-06 15:00:03

标签: sql sql-server tsql sql-server-2000

当表FI_CurrentReceiptData只有2行时,我有以下查询返回4个结果。额外的行是完全重复的。我可以使用DISTINCT来修复,但我的理解是这是不好的做法,我会更好地找到并纠正错误(这是正确的吗?)。

为什么此查询会将结果加倍?

所有变量都在存储过程的其他地方声明,并且此查询会返回所需的字段。

SELECT ( (Select Max(ReceiptNumber)
          from   Avanti_InventoryReceipts) + CR.Seq ),
       CR.ItemNumber,
       Convert(char(8), GETDATE(), 112),
       PONum,
       'FL-INV',
       PH.POVendor,
       0,
       0,
       'O',
       CR.QtyOrdered,
       QtyReceivedToday,
       QtyReceivedToday,
       Case @closePO
         When 'N' Then Case
                         When ( QtyOrdered - QtyReceivedToday ) < 0 Then 0
                         Else ( QtyOrdered - QtyReceivedToday )
                       End
         When 'Y' Then 0
         Else 0
       End,
       PD.TransCost * QtyReceivedToday,
       IH.PriceWholeSale,
       IH.CostLast,
       QtyReceivedToday,
       0,
       '',
       PODetailDescription /* , .... More columns...*/

FROM   FI_CurrentReceiptData CR
       LEFT JOIN Avanti_PODetails PD
         ON CR.PONum = PD.PONumber
       LEFT JOIN Avanti_POHeader PH
         ON CR.PONum = PH.PONumber
       LEFT JOIN Avanti_InventoryHeader IH
         ON CR.ItemNumber = IH.ItemNumber  

NEW WHERE CLERE解决方案:

FROM FI_CurrentReceiptData CR
inner JOIN Avanti_PODetails PD ON CR.PONum = PD.PONumber AND CR.ItemNumber = PD.TransItem AND CR.QtyOrdered = PD.TransQty
left JOIN Avanti_POHeader PH ON PD.PONumber = PH.PONumber
left JOIN Avanti_InventoryHeader IH ON CR.ItemNumber = IH.ItemNumber

3 个答案:

答案 0 :(得分:3)

通常当你将左连接字符串组合在一起时,你必须继续加入'左'表 - 这不是一个规则,而是它的良好做法,所以你不要错过连接。在您的左连接字符串中,它包含4个表,您只将第一个连接到所有三个表:


FROM   FI_CurrentReceiptData CR 
       LEFT JOIN Avanti_PODetails PD 
         ON CR.PONum = PD.PONumber 
       LEFT JOIN Avanti_POHeader PH 
         ON CR.PONum = PH.PONumber 
       LEFT JOIN Avanti_InventoryHeader IH 
         ON CR.ItemNumber = IH.ItemNumber   


你没有将PD加入IH到PH,但基本上是将CR表连接到所有三个 - 所以基本上它是在PD和PH和IH之间进行交叉连接(基于它们匹配的任何字段)。我假设POheader和POdetails有一些匹配的字段....我假设它们之间的一对多关系? (根据名称)。所以那里需要有一些限制......

编辑:

你可以尝试,(根据田野关系)


FROM   FI_CurrentReceiptData CR 
       LEFT JOIN Avanti_PODetails PD 
         ON CR.PONum = PD.PONumber 
       LEFT JOIN Avanti_POHeader PH 
         ON CR.PONum = PH.PONumber AND PD.PONumber = PH.PONumber
       LEFT JOIN Avanti_InventoryHeader IH 
         ON CR.ItemNumber = IH.ItemNumber   


编辑2:

好的,所以你说的是,CR有2行,CR与PH有一对一的关系,PH与PD的关系是1对多。 CR也与IH有一对一的关系。在这种情况下,假设您具有参考完整性,您可以将您的联接更改为:


FROM   FI_CurrentReceiptData CR 
       LEFT JOIN Avanti_POHeader PH ON CR.PONum = PD.PONumber 
       INNER JOIN Avanti_PODetails PD ON PH.PONumber = PD.PONUmber
       LEFT JOIN Avanti_InventoryHeader IH ON CR.ItemNumber = IH.ItemNumber

让我们退后一步 - 这将根据它们是否匹配来限制PD和PH行,并且即使它们不匹配也不会得到空值(这是左连接所做的)。

但是现在,如果CR中有2行,并且每个PONumbers在POHeader中有2行,并且每个POheader在POdetails中有超过1行,那么你肯定会有重复。真的没有办法避免这种情况。原因是:

CR TABLE


PONum            ItemNumber
---------        ----------
123              ABC
456              DEF

PH TABLE


PONumber     
---------        
123              
456              

PD TABLE


PONumber     ItemNumber     
---------    -----------    
123          ABC    
123          ABC1
456          DEF
456          DEF1    

...如果您将CR表连接到PH表,您将只获得两行。如果您将PH加入PD表,那么您将有4行。如果你加入所有3,那么你也将获得4行。连接的性质遍及所有表,因此当您从CR表转到PH时,它会获得2行的结果集...然后该结果集将连接到PD,并且有4行。如果您可以确认您的数据是这样的,那么您获得的结果集是正确的。

答案 1 :(得分:1)

由于您正在进行LEFT JOINS,因此所有匹配记录都会返回1行。因此,您加入的其中一个表格返回的行数超过1行。

尝试临时更改查询以将其他表主键添加到列列表中,您应该能够快速判断哪个表返回的行超过1行。

答案 2 :(得分:0)

其中一个连接表有多个匹配行。 我无法确定哪一个,但如果我是你,我会开始寻找 在Avanti_PODetails表中。它对两个收据中的任何一个都有多个匹配记录吗?