最后两个连接会导致重复的行

时间:2014-02-04 17:11:59

标签: sql sql-server join

好的,所以我的查询返回的行数多于预期的重复数据。这是我的疑问:

SELECT AP.RECEIPTNUMBER
,AP.FOLDERRSN
,ABS(AP.PAYMENTAMOUNT)
,ABS(AP.PAYMENTAMOUNT - AP.AMOUNTAPPLIED)
,TO_CHAR(AP.PAYMENTDATE,'MM/DD/YYYY')
,F.REFERENCEFILE
,F.FOLDERTYPE
,VS.SUBDESC
,P.NAMEFIRST||' '||P.NAMELAST
,P.ORGANIZATIONNAME
,VAF.FEEDESC
,VAF.GLACCOUNTNUMBER

FROM ACCOUNTPAYMENT AP

INNER JOIN FOLDER F ON AP.FOLDERRSN = F.FOLDERRSN
INNER JOIN VALIDSUB VS ON F.SUBCODE = VS.SUBCODE
INNER JOIN FOLDERPEOPLE FP ON FP.FOLDERRSN = F.FOLDERRSN
INNER JOIN PEOPLE P ON FP.PEOPLERSN = P.PEOPLERSN
INNER JOIN ACCOUNTBILLFEE ABF ON F.FOLDERRSN = ABF.FOLDERRSN
INNER JOIN VALIDACCOUNTFEE VAF ON ABF.FEECODE = VAF.FEECODE

WHERE AP.NSFFLAG = 'Y'
AND F.FOLDERTYPE IN ('405B','405O')

一切正常,直到我添加底部的两个内连接。我基本上都试图获得所有支付NSF的款项。当我运行简单查询时:

SELECT *
FROM ACCOUNTPAYMENT
WHERE NSFFLAG = 'Y'

我只获得了与405B和405O文件夹相关的3行。所以我只期望在上面的查询中返回3行,但我得到9行,在某些列中重复信息。我需要根据有效帐户费用和帐户帐单费用表中的费用代码确切的feedesc和gl帐号。

我无法发布我的输出图片。

注意:当我在没有两个底部连接的情况下运行查询时,我得到了预期的输出。

有人可以帮助我提高查询效率吗?谢谢!

根据要求,以下是我的查询为vaf.feedesc和vaf.glaccountnumber列返回的结果:

Boiler Operator License Fee                                         2423809
Boiler Certificate of Operation without Manway - Revolving          2423813
Installers (Boiler License)/API Exam                            2423807
Boiler Public Inspection/Certification (State or Insurance)         2423816
Boiler Certificate of Operation with Manway                         2423801
Boiler Certificate of Operation without Manway                  2423801
Boiler Certificate of Operation with Manway - Revolving         2423813
BPV Owner/User Program Fee                                          2423801
Installers (Boiler License)/API Exam Renewal                    2423807

3 个答案:

答案 0 :(得分:10)

原因是至少有一个连接ACCOUNTBILLFEE-FOLDERVALIDACCOUNTFEE-ACCOUNTBILLFEE不是一对一的。它允许一个文件夹具有多个 AccountBillFees ,或者允许一个 ValidAccountFee 具有多个 AccountBillFees

要找到这种问题的原因,我通常会这样做:

  • 将查询的SELECT A, B, C部分更改为SELECT *
  • 将结果减少到导致您遇到麻烦的行之一(通过添加WHERE ...)。这是没有最后两个连接的单行和添加这两个连接后的几行。
  • 从左到右查看结果表。第一列可能会显示所有行的相同值。一旦看到列中值之间的差异,您就会知道当前正在查看的列表导致了“多行问题”。
  • 现在创建一个SELECT *语句,其中只包含连接在一起的两个表,这两个表会导致多行与您上面使用的WHERE ...相同。
  • 结果应该能让您清楚了解原因。
  • 一旦你知道问题的原因,你就可以想到一个解决方案;)

答案 1 :(得分:0)

尝试此操作如果它有帮助那么这些表有额外的行不相关。如果没有,那么请查看我下面的子查询的结果,看看需要哪些额外的过滤器

SELECT AP.RECEIPTNUMBER
,AP.FOLDERRSN
,ABS(AP.PAYMENTAMOUNT)
,ABS(AP.PAYMENTAMOUNT - AP.AMOUNTAPPLIED)
,TO_CHAR(AP.PAYMENTDATE,'MM/DD/YYYY')
,F.REFERENCEFILE
,F.FOLDERTYPE
,VS.SUBDESC
,P.NAMEFIRST||' '||P.NAMELAST
,P.ORGANIZATIONNAME
,VAF.FEEDESC
,VAF.GLACCOUNTNUMBER

FROM ACCOUNTPAYMENT AP

INNER JOIN FOLDER F ON AP.FOLDERRSN = F.FOLDERRSN
INNER JOIN VALIDSUB VS ON F.SUBCODE = VS.SUBCODE
INNER JOIN FOLDERPEOPLE FP ON FP.FOLDERRSN = F.FOLDERRSN
INNER JOIN PEOPLE P ON FP.PEOPLERSN = P.PEOPLERSN
INNER JOIN 
(
   SELECT DISTINCT ABF.FEECODE, ABF.FOLDERRSN
   FROM ACCOUNTBILLFEE ABF
) ABF ON F.FOLDERRSN = ABF.FOLDERRSN
INNER JOIN 
(
  SELECT DISTINCT VAF.FEEDESC, VAF.GLACCOUNTNUMBER, VAF.FEECODE
  FROM VALIDACCOUNTFEE VAF
) VAF ON ABF.FEECODE = VAF.FEECODE
WHERE AP.NSFFLAG = 'Y'
AND F.FOLDERTYPE IN ('405B','405O')

答案 2 :(得分:0)

最后两个表的数据在一对多关系中的不同记录中是不同的。由于distinct不能解决问题,因此您必须接受9条记录是正确的返回,因为您返回的是不同的字段,或者您必须根据业务规则确定您不希望返回的多条记录中的哪条记录必须来自你公司的某个人,而不是我们。

我不认为你完全理解SQl是如何工作的,因为根据你在问题中给出的信息,9条记录正是我所期望的。以下是一些查询,显示如何加入一对多关系可以影响输出以及您可以调整查询以摆脱重复输出的方式。

请注意,在某些情况下,由于要返回的列,无法调整查询以消除输出。因此,即使某些列被重复,如果您想要返回的列中有一个列具有不同的记录,并且您没有想要查看其中哪些列的适当业务规则,则无法减少记录集。您需要哪些规则取决于您查询的数据类型以及所需的规则。这不是我们可以在这里回答的问题,只有您的公司知道最小值或最大值是否可接受,或者您是否需要添加where子句,如果需要,可以使用哪个字段以及使用它来排除的值。这些是业务规则而不是SQL。

create table #temp (myid int , mydescription varchar(30))

insert into #temp(myid, mydescription)
values (1, 'test') , (2, 'test2')

create table #temp2 (myid int, myotherdescription varchar(30))

insert into #temp2(myid, myotherdescription)
values (1, 'othertest') , (1, 'othertest2'), (2, 'myothertest') , (1, 'othertest3')

select * 
from #temp t
join #temp2 t2 on t.myid = t2.myid

select t2.myid, t.mydescription
from #temp t
join #temp2 t2 on t.myid = t2.myid

select distinct t2.myid, t.mydescription
from #temp t
join #temp2 t2 on t.myid = t2.myid

select t.myid, t.mydescription, t2.myotherdescription
from #temp t
join #temp2 t2 on t.myid = t2.myid

select distinct t.myid, t.mydescription, t2.myotherdescription
from #temp t
join #temp2 t2 on t.myid = t2.myid

select t.myid, min(t2.myotherdescription)
from #temp t
join #temp2 t2 on t.myid = t2.myid
group by t.myid

select t.myid, t2.myotherdescription
from #temp t
join #temp2 t2 on t.myid = t2.myid
where  t2.myid = 2