首先:我知道使用所有类型的联接,但是我不知道为什么该查询对这种查询如此工作
我有一个通过使用3个表以及在销售和订购商品之间进行左外部联接来进行SQL查询的方案。
我的桌子:
--------------------
Item
--------------------
ID | Code
--------------------
1 | 7502
SQL > select * from Item where id = 1
---------------------
Item_Order
---------------------------
Item | Box | Quantity
---------------------------
1 | 30 | 15000
1 | 12 | 6000
SQL > select * from Item_Order where Item = 1
--------------------------
Invoice_Item
-------------------
Item | Num | Quantity
-------------------------
1 | 1.64 | 10
1 | 2.4 | 8
SQL > select * from Invoice_Item where Item = 1
我想要这个输出:
Item | OrderQ | OrderB | SellN | SellQ
-----------------------------------------
1 | 1500 | 30 | 1.64 | 10
1 | 6000 | 12 | 2.4 | 8
我的SQL代码:
SELECT Item.ID, Item_Order.Box As OrderB, Item_Order.Quantity As OrderQ, Invoice_Item.Num As SellN, Invoice_Item.Quantity As SellQ
FROM Item LEFT OUTER JOIN
Invoice_Item ON Item.ID = Invoice_Item.Item LEFT OUTER JOIN
Item_Order ON Item_Order.Item = Item.ID
where Item.ID = 1
为什么我的输出是2倍?或为什么我的输出返回4条记录?
答案 0 :(得分:1)
您可以使用row_number
来获得结果:
select a.ID
, a.OrderB
, a.OrderQ
, b.Quantity SellQ
, b.Num SellN
from
(SELECT Item.ID
, Item_Order.Box As OrderB
, Item_Order.Quantity As OrderQ
, row_number () over (order by Item.ID) rn
FROM Item
left outer JOIN Item_Order ON Item.ID = Item_Order.Item) a
left outer join (select Item
, Num
, Quantity
, row_number () over (order by Item) rn
from Invoice_Item ) b
on a.ID = b.Item
and a.rn = b.rn
您可以添加更多这样的表:
left outer join (select Item
, Num
, Quantity
, row_number () over (order by Item) rn
from Invoice_Item ) b
答案 1 :(得分:0)
这是重复的,因为您在Invoice_Item和Item_Order之间没有辅助关联。对于Invoice_Item中的每个记录,它仅基于Item ID匹配到Item_Order(称为笛卡尔结果)。因此,您的订单数量显示为1:1引用,因此第一个发票项目数量10为MEANT,将与Item_Order Box = 30关联。数量8为MEANT,与Item_Order Box = 12相关。
Item_Order
Item Box Quantity
1 30 15000
1 12 6000
Invoice_Item
Item Num Quantity
1 1.64 10
1 2.4 8
您可能需要添加“ Box”引用,以便Item_Order和Invoice_Item为1:1匹配。
发生的是发票项目中的每个项目都根据项目ID连接到Item_Order。所以你得到两个。如果您有3个发票项目,分别具有Items_Order的1和6,则将获得18行。
反馈
即使您已经收到基于OVER / PARTITION / ROW NUMBER的答案,该过程仍在向每行强制添加辅助ID。对于整个数据结构关联而言,依靠这种方法并不是最好的选择。如果删除订单上的第二个项目,会发生什么。您确定要删除invoice_items中的第二个项目吗?
关于在原始方案中返回2条记录,您可以通过代理过程,但是我认为长期来看了解联接中发生的情况会更好。返回到Item_Order和Invoice_Item的示例数据。因此,让我们从Item_Order表开始。 SQL引擎将单独处理每一行。
第一行SQL抓取Item = 1,Box = 30,数量= 15000。
因此,现在它联接到“发票物料”表,并且由于您的条件,它仅基于物料联接。因此,它看到第一行并说...是的,这是项目1,因此将其与项目订单记录一起包含在内(返回的第一行)。现在,它转到发票项目表的第二行...是的,它也与项目1相同,因此它又返回了它(返回了第二行)。
现在,SQL抓取第二行Item = 1,Box = 12,数量= 6000。
返回到“发票项目”表,并执行完全相同的测试...,并针对具有项目= 1的项目订单中的每一行,以及第三和第四行,因此您加倍...如果任一表中都有更多记录使用相同的商品ID,它将返回更多记录... 3和3条记录将返回9行。 4和4记录将返回16行,依此类推。进行替代可以工作,但是我认为没有更好/更新的设计结构那么安全。
答案 2 :(得分:0)
因为当您第一次将Item
与Item_Order
连接时,它会输出两条记录,因为Item_Order
中有两条记录。现在,此结果查询将与Invoice_Item
保持连接,并且两个记录将与Invoice_Item
的所有记录一起连接
您可以这样更好地理解
SELECT Item.ID, Item_Order.Box As OrderB, Item_Order.Quantity As OrderQ, Invoice_Item.Num As SellN, Invoice_Item.Quantity As SellQ
FROM Item LEFT OUTER JOIN
Invoice_Item ON Item.ID = Invoice_Item.Item LEFT OUTER JOIN
where Item.ID = 1 into table4 //Only to explain
现在,第一个查询table4
的结果将与Items_Order
合并
答案 3 :(得分:0)
您正在连接一个键-在一个表中使用同一键的两行乘以第二个表中的两行= 4行。
您需要一个单独的密钥。您可以使用row_number()
生成一个:
SELECT i.ID, io.Box As OrderB, io.Quantity As OrderQ,
ii.Num As SellN, ii.Quantity As SellQ
FROM Item i LEFT OUTER JOIN
((SELECT ii.*,
ROW_NUMBER() OVER (PARTITION BY ii.item ORDER BY ii.item) as seqnum
FROM Invoice_Item ii
) FULL JOIN
(SELECT io.*,
ROW_NUMBER() OVER (PARTITION BY io.item ORDER BY io.item) as seqnum
FROM Item_Order io
) io
ON io.Item = ii.ID AND io.seqnum = ii.seqnum
)
ON i. = ii.Item
where i.ID = 1;
请注意,这是在FROM
子句中使用括号的少数情况之一。这段代码可以处理两个表中的其他行-如果一个表比另一个表长,则另一个表的列将为NULL
。
如果您知道两个表(给定项目)的行数相同,则可以使用内部联接,而不必使用括号。