Oracle SQL-表与不正确数据输出之间的1:M关系上的左联接

Oracle SQL-表与不正确数据输出之间的1:M关系上的左联接,sql,oracle,join,distinct,Sql,Oracle,Join,Distinct,我想使用左连接连接多个表。我当前在连接中获得重复记录和不一致的数据。有什么想法吗 我相信我找到了解决重复记录的方法,但我不确定它是否可靠 在本例中,下订单时,应将其附加到与订单关联的任何项目以及与发票关联的任何客户端。Items和Client表基本上是静态的,只有在添加新的Items或Client时才会更新,这并不常见 这是一个小规模的例子,整个数据集大约有600万行 订单与订单详细程度的关系为1:M 发票与订单的关系为M:1,与订单详细程度的关系为M:M 客户端仅与具有1:1关系的发票关联 项

我想使用左连接连接多个表。我当前在连接中获得重复记录和不一致的数据。有什么想法吗

我相信我找到了解决重复记录的方法,但我不确定它是否可靠

在本例中,下订单时,应将其附加到与订单关联的任何项目以及与发票关联的任何客户端。Items和Client表基本上是静态的,只有在添加新的Items或Client时才会更新,这并不常见

这是一个小规模的例子,整个数据集大约有600万行

订单与订单详细程度的关系为1:M

发票与订单的关系为M:1,与订单详细程度的关系为M:M

客户端仅与具有1:1关系的发票关联

项目与订单详细信息的关系为1:M

选择DISTINCT
(按a.apk顺序按a.apk desc分区)上的行数()作为SEQNUM
从桌子上
其中SEQNUM=1

当前解决方案

SELECT DISTINCT
a.apk
,a.DATE
,bc.CATEGORY
,bc.ITEMNAME
,bc.amt
,d.clientname
,e.invoiceid
,row_number() over (partition by a.apk order by a.apk desc) as SEQNUM
FROM atable a 
LEFT JOIN 
    (SELECT DISTINCT
     tableb.amt
     ,tableb.apk
     ,tablec.CATEGORY
     ,tablec.ITEMNAME
     FROM tableb b 
        LEFT JOIN tablec c ON (b.cpk = c.cpk)) bc
     ON (a.apk = bc.apk)
LEFT JOIN 
    (SELECT DISTINCT
     d.clientname
     ,e.invoiceid
     ,e.epk
     ,d.dpk
     FROM tabled d 
        LEFT JOIN tableE e ON (d.dpk = e.epk)) ed
     ON (a.apk = ed.apk)
WHERE SEQNUM = 1
样本数据

表A(订单)
主键:apk

apk  DATE      
1    8/17/17   
bpk  apk  cpk amt
1    1    1   5
2    1    2   100
cpk ITEMNAME     ITEMID  CATEGORY    
1   Tape         1234    Office Supplies   
2   Toner        5678    Printer Supplies
epk apk dpk INVOICEID  INVOICE_DATE
1   1   5   776        8/18/17
2   1   6   934        8/19/17
表B(订单详细程度)
主键:bpk

apk  DATE      
1    8/17/17   
bpk  apk  cpk amt
1    1    1   5
2    1    2   100
cpk ITEMNAME     ITEMID  CATEGORY    
1   Tape         1234    Office Supplies   
2   Toner        5678    Printer Supplies
epk apk dpk INVOICEID  INVOICE_DATE
1   1   5   776        8/18/17
2   1   6   934        8/19/17
表C(项目)
主键:cpk

apk  DATE      
1    8/17/17   
bpk  apk  cpk amt
1    1    1   5
2    1    2   100
cpk ITEMNAME     ITEMID  CATEGORY    
1   Tape         1234    Office Supplies   
2   Toner        5678    Printer Supplies
epk apk dpk INVOICEID  INVOICE_DATE
1   1   5   776        8/18/17
2   1   6   934        8/19/17
表D(客户端)
主键:dpk

dpk  CLIENTNAME
5    STAPLES
6    WALMART
表E(发票)
主键:epk

apk  DATE      
1    8/17/17   
bpk  apk  cpk amt
1    1    1   5
2    1    2   100
cpk ITEMNAME     ITEMID  CATEGORY    
1   Tape         1234    Office Supplies   
2   Toner        5678    Printer Supplies
epk apk dpk INVOICEID  INVOICE_DATE
1   1   5   776        8/18/17
2   1   6   934        8/19/17
当前结果

apk DATE    CATEGORY        ITEMNAME  amt    CLIENTNAME    INVOICEID
1   8/17/17 Office Supplies Tape      5      Staples       776       
1   8/17/17 Office Supplies Tape      100    Walmart       934
1   8/17/17 Office Supplies Tape      5      Staples       776       
1   8/17/17 Office Supplies Tape      100    Walmart       934
1   8/17/17 Office Supplies Tape      100    Walmart       934       
1   8/17/17 Office Supplies Tape      100    Walmart       934
预期结果

apk DATE    CATEGORY         ITEMNAME     amt    CLIENTNAME    INVOICEID
1   8/17/17 Office Supplies  Tape         5      Staples       776       
1   8/17/17 Printer Supplies Toner        100    Walmart       934
提前谢谢


编辑:数据,澄清

如果我们假设发票表有cpk列

Table E (Invoice) Primary Key: epk

epk apk cpk dpk INVOICEID
1   1   1   5   776
2   1   2   6   934
SQL查询将是

SELECT os.apk,
       os.ord_dt,
       it.category,
       it.itemname,
       od.amt,
       cs.clientname,
       ie.invoiceid
  FROM orders os
 INNER JOIN order_dtl od
    ON os.apk = od.apk
 INNER JOIN items it
    ON od.cpk = it.cpk
 INNER JOIN invoice ie
    ON ie.apk = od.apk
   AND ie.cpk = od.cpk
 INNER JOIN clients cs
    ON cs.dpk = ie.dpk;
结果

       APK ORD_DT    CATEGORY             ITEMNAME          AMT CLIENTNAME  INVOICEID
---------- --------- -------------------- ---------- ---------- ---------- ----------
         1 17-AUG-17 Office Supplies      Tape                5 STAPLES           776
         1 17-AUG-17 Printer Supplies     Toner             100 WALMART           934

我认为您应该将
bpk
添加到
invoice
表中,或者将
epk
添加到
order details
中,以便在这些表之间建立连接。否则我们不知道碳粉是史泰博还是沃尔玛订购的

但在当前数据模型中,假设
订单详细信息中的第一个项目与
发票中的第一个位置匹配,我们可以使用
行编号()。我所说的“第一”是指id较低的:

select apk, adate, category, itemname, amt, clientname, invoiceid
  from a
  join (select b.*, row_number() over (partition by apk order by bpk) rn 
          from b) b using (apk)
  join c using (cpk)
  join (select e.*, row_number() over (partition by apk order by epk) rn 
          from e) e using (apk, rn)
  join d using (dpk)
演示:

结果:

   APK ADATE       CATEGORY         ITEMNAME        AMT CLIENTNAME  INVOICEID
------ ----------- ---------------- -------- ---------- ---------- ----------
     1 2017-08-17  Office Supplies  Tape              5 Staples           776
     1 2017-08-17  Printer Supplies Toner           100 Wallmart          934

我不明白您是如何决定在预期结果的最后两个属性中选择值的。apk有两个选项(staples和wallmart),因此,为什么第一行有staples,第二行有walmart,第二行有偶数赏金(加上属于walmart的934)?实际上,如果只执行内部联接,则得到6行。你的回答不清楚你的预期结果是如何产生的。这个问题毫无意义。例如,在您的表数据中,“磁带”的cpk=1,已知一个金额值:3,但在您当前和所需的输出中,您将“磁带”的数量链接为5。“纸巾”的数量仅为100,但在您想要的输出中,您想要3@RadimBača我们的数据就是这样在我这边建立的。例如,一张发票可能包含多个项目,每个项目都与一个客户关联。我试图复制我这边的样子。对这里的任何混乱表示歉意。为了澄清,我删除了第三项。@trincot我删除了第三项并进行了相应调整。我只是不明白为什么在提取任何数据时,它会在所有行上提取不正确的项目名称和类别。