Transact SQL子查询

时间:2017-10-02 18:27:09

标签: sql-server subquery

我想要一个查询,它会返回所有订单行项目都有库存的订单的Order_ID列表。以下是要说明的表格:

test_Order:

Order_ID
1001
1002
1003

test_OrderLine:

OrderLine_ID|Order_ID|Item_ID|Quantity
10|1001|101|1
11|1001|102|1
12|1001|103|1
13|1002|101|4
14|1002|102|1
15|1003|101|1
16|1003|104|4

test_Item:

Item_ID|InStockQuantity
101|3
102|1
103|7

因此,在上面的示例中,只应返回Order_ID 1001,因为:

  • 在订单1001中,OrderLines中的所有3个项目的数量都小于或等于项目中的InStockQuantity。
  • 在1002的订单中,项目101的数量为4,但库存中只有3个。
  • 在订单1003中,项目表中不存在项目104。

这显然不正确,但有点像:

SELECT O.Order_ID
FROM test_Order AS O
  LEFT JOIN test_OrderLine OL
    ON O.Order_ID = OL.Order_ID
  LEFT JOIN test_Item I
    ON OL.Item_ID = I.Item_ID
WHERE (OL.Quantity <= I.InStockQuantity)
GROUP BY O.Order_ID

该查询的问题在于,只有一个OrderLines需要有一个Quantity&lt; = InStockQuantity才能使Order_ID出现在结果中,而我只希望它出现在结果中,如果订单中的所有数量都是&lt; = InStockQuantities。

我读了一些关于“ALL”运算符的内容,但看不出它在子查询中是如何工作的。

3 个答案:

答案 0 :(得分:0)

考虑此问题的另一种方法是返回没有订单行的order_ids,订单行的数量大于库存数量。使用左连接和coalesce可以让您完全缺货,就像它们的数量为0一样:

SELECT order_id
FROM   test_order
WHERE  order_id NOT IN (SELECT    order_id
                        FROM      test_orderline o
                        LEFT JOIN test_item i ON o.item_id = i.item_id 
                        WHERE     o.quantity > COALESCE(i.instockquantity, 0))

答案 1 :(得分:0)

使用not exists()

select o.Order_id
from test_Order as o
where not exists (
    select 1
    from test_OrderLine as ol
      left join test_Item as i
        on ol.Item_id = i.Item_id
    where ol.Order_id = o.Order_id
      and OL.Quantity > coalesce(I.InStockQuantity,0)
  )

rextester演示:http://rextester.com/JGHQ62465

返回:

+----------+
| Order_id |
+----------+
|     1001 |
+----------+

答案 2 :(得分:0)

这是一个小提琴:http://rextester.com/UPC62237

我相信这可以满足您的需求。我评论说你可以理解查询背后的逻辑。

create table test_Order ([Order_id] int); 
insert into test_Order ([Order_id]) values 
 (1001)
,(1002)
,(1003);
create table test_OrderLine ([OrderLine_id] int, [Order_id] int, [Item_id] int, [Quantity] int) ; 
insert into test_OrderLine ([OrderLine_id], [Order_id], [Item_id], [Quantity]) values 
 (10, 1001, 101, 1) 
,(11, 1001, 102, 1)
,(12, 1001, 103, 1)
,(13, 1002, 101, 4)
,(14, 1002, 102, 1)
,(15, 1003, 101, 1)
,(16, 1003, 104, 4)
;
create table test_Item ([Item_id] int, [InStockQuantity] int) ; 
insert into test_Item ([Item_id], [InStockQuantity]) values 
 (101, 3)
,(102, 1)
,(103, 7)
;

select original_orderline_count.Order_id 
/*first table gets each order with it's line count*/
from (select order_line.Order_id, count(order_line.OrderLine_id) as line_count
        from test_OrderLine order_line
        group by order_line.Order_id) as original_orderline_count
/*second table gets count of order lines in stock by order*/
inner join (select ol.Order_id, count(ol.OrderLine_id) as line_count
            from test_Order o
            inner join test_OrderLine ol on o.Order_id = ol.Order_id
            inner join test_Item i on i.Item_id = ol.Item_id
            where ol.Quantity <= i.InStockQuantity
            group by ol.Order_id) as orderline_in_stock
/*join the two tables on order id line count matching*/         
on original_orderline_count.Order_id = orderline_in_stock.Order_id
and original_orderline_count.line_count = orderline_in_stock.line_count