【问题标题】:Oracle: Joining on TOP 1 recordOracle:加入 TOP 1 记录
【发布时间】:2015-11-29 12:12:24
【问题描述】:

我在这里看到了一些类似问题的答案,但还不能完全正确地实现。

我想在 2 个应该创建一对一关系的 oracle 表之间创建一个 JOIN。不幸的是,由于我的第二个表的设置,它返回一个一对多的关系。

这是我的两张桌子。 “项目”包含项目名称和项目的批号。然后,我需要进入我们的“Item_Inventory”表以查找该项目当前是否有库存(如果该项目当前不在此表中,则它没有库存)。

===========================
ITEMS
===========================
Item_No     |   Lot_Num
---------------------------
SHP-705-F   |   X456588R
BAG-DRAWSTR |   Y245899Z
ALC-6697-MI |   A237520P
---------------------------

=======================================================
ITEM_INVENTORY
=======================================================
Item_No     |   Lot_Num    |  BIN_LOC  |  QTY_ONHAND 
-------------------------------------------------------
SHP-705-F   |   X456588R   |   P8541E  |     82      
SHP-705-F   |   X456588R   |   Q8870Q  |     82      
SHP-705-F   |   X456588R   |   U4142B  |     82      
BAG-DRAWSTR |   Y245899Z   |   P5888D  |     15
BAG-DRAWSTR |   Y245899Z   |   R5588Z  |     15
BAG-DRAWSTR |   Y245899Z   |   W8339A  |     15
-------------------------------------------------------

这是我的查询:

SELECT i.Item_No, i.Lot_Num 
FROM ITEMS i
JOIN ITEM_INVENTORY inv ON inv.Item_No = i.Item_No AND inv.Lot_Num = i.Lot_Num

这是我要退货的(注意项目“ALC-6697-MI”被排除在外,因为它在 Item_Inventory 表中没有当前库存):

Item_No     |   Lot_Num
---------------------------
SHP-705-F   |   X456588R
BAG-DRAWSTR |   Y245899Z

相反,由于 Item_Inventory.Bin_Loc 字段,我在 JOIN 时得到了这个:

Item_No     |   Lot_Num    
-------------------------
SHP-705-F   |   X456588R     
SHP-705-F   |   X456588R      
SHP-705-F   |   X456588R      
BAG-DRAWSTR |   Y245899Z  
BAG-DRAWSTR |   Y245899Z  
BAG-DRAWSTR |   Y245899Z  

我怎样才能加入这两个表,但保持一对一的关系?

谢谢

【问题讨论】:

  • 请出示您的查询。
  • 抱歉,已更新以包含我的查询

标签: oracle join oracle11g oracle10g oracle-sqldeveloper


【解决方案1】:

选项 1:只需在 select 子句中添加 distinct:

select distinct ITEMS.Item_No, ITEMS.Lot_Num
from ... /* the rest of your query*/

选项2:使用exists子句:

select i.Item_No, i.Lot_Num
from ITEMS i
where exists (
    select *
    from ITEM_INVENTORY inv
    where inv.Item_no = i.Item_no and inv.Lot_Num = i.Lot_Num
)

【讨论】:

  • EXISTS 查询中的一个不错的;我应该自己发现的! *{;-) 另外,我将 distinct 向下推到子查询中以减少加入的行数。在这种情况下可能没有什么不同,但需要注意一些事情。
  • 是的。将 distinct 移至子查询并没有真正的大改进。一旦找到满足存在子句的第一个元组,DBMS 就不需要继续检查剩余的元组。 ;-)
  • 在 exists 子句中使用 distinct 运算符是不必要的,甚至可能对查询性能有害。 BTW @Jodevan 您可能应该在子查询 where 子句中包含 and inv.lot_num = i.lot_num 谓词。正如@Boneist 和我在回复中所做的那样,除非 OP 在检查库存时不关心批号。
  • 正如 Sentinel 暗示的那样,我并不是建议在存在查询中使用 DISTINCT,而是在您的第一个查询中使用。回读我的评论,这不是很明显,对不起!
  • @Jodevan 您的简单选择是所述问题的绝佳解决方案,除非 OP 需要问题陈述中未提及的 ITEMS 表中的一些数据。您应该将其添加为答案。
【解决方案2】:

您可以使用 in 子句:

select i.Item_No, i.Lot_Num
  from ITEMS i
 where (i.Item_No, i.Lot_Num)
    in (select inv.Item_No, inv.Lot_Num
          from ITEM_INVENTORY inv
         where inv.Item_no = i.Item_no
           and inv.Lot_Num = i.Lot_Num)

通过省略where inv.Item_no = i.Item_no and inv.Lot_Num = i.Lot_Num 子句,上面的子查询可以是相关的(如图所示)或不相关的。

【讨论】:

    【解决方案3】:

    在加入两个表之前,最简单且(可能,但您必须测试您的数据)最快的是在加入两个表之前执行不同的操作,例如。类似:

    select *
    from   items i
           inner join (select distinct item_no, lot_num from item_inventory) ii on (ii.item_no = i.item_no and ii.lot_num = i.lot_num);
    

    您还可以为库存表中项目组中的每一行分配一个编号,但这可能需要更长的时间。当然,您必须进行测试!例如

    select *
    from   items i
           inner join (select item_no, lot_num, row_number() over (partition by item_no, lot_num order by bin_loc) rn from item_inventory) ii on (ii.item_no = i.item_no and ii.lot_num = i.lot_num and ii.rn = 1);
    

    【讨论】:

      猜你喜欢
      • 2011-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-17
      相关资源
      最近更新 更多