复杂的SQL查询 - 连接具有复杂条件的5个表

时间:2014-07-29 14:56:29

标签: sql join group-by progress-db

我有以下表格:预订,订单行,订单标题,产品,客户。只是对每个表格做一点解释:

  • 预订包含结算客户/产品组合的“预订”。
  • 订单行包含订单的订单项详细信息,包括订购的产品和数量。
  • 订单标题包含订单的标题信息,包括日期,客户和结算客户
  • 产品包含产品详细信息
  • 客户包含客户详细信息。

以下是包含相关字段和示例数据的表格:

Reservation
bill-cust-key  prod-key  qty-reserved  reserve-date
10000          20000     10            05/30/2014
10003          20000     5             06/20/2014
10003          20001     15            06/20/2014
10003          20001     5             06/25/2014
10002          20001     5             06/21/2014
10002          20002     20            06/21/2014

Order-Item
order-num   cust-key    prod-key    qty-ordered
30000       10000       20000       10
30000       10000       20001       5
30001       10001       20001       10
30002       10001       20001       5
30003       10002       20003       20

Order-Header
order-num   cust-key    bill-cust-key   order-date
30000       10000       10000           07/01/2014
30001       10001       10003           07/03/2014
30002       10001       10003           07/15/2014
30003       10002       10002           07/20/2014

Customer
cust-key    cust-name
10000       Customer A
10001       Customer B
10002       Customer C
10003       Customer D

Product
prod-key    prod-name
20000       Prod A
20001       Prod B
20002       Prod C
20003       Prod D

我正在尝试编写一个查询,向我显示预订和订单项表中都存在的客户/产品组合。有点麻烦的是,我们有一个客户和一个结算客户。预订和订单表头表包含客户,但订单商品表仅包含客户。结果应显示结算客户。此外,同一客户/产品组合可能有多个预订和订单商品,因此我想显示qty-reserved和qty-ordered的总和。

以下是我所需输出的示例:

bill-cust-key   cust-name   prod-key    prod-name   qty-ordered qty-reserved
10000           Customer A  20000       Prod A      10          10
10003           Customer D  20001       Prod B      15          20

这是我尝试过的查询,似乎对我没用。

SELECT customer.cust-key, customer.cust-name, product.prod-key, prod.prod-name,
     SUM(order-item.qty-ordered), SUM(reservation.qty-reserved)
FROM ((reservation INNER JOIN order-item on reservation.prod-key = order-item.product-key)
     INNER JOIN order-header on reservation.bill-cust-key = order-header.bill-cust-key and    
     order-item.order-num = order-header.order-num), customer, product
WHERE customer.cust-key = reservation.bill-cust-key
AND product.prod-key = reservation.prod-key
GROUP BY customer.cust-key, customer.cust-name, product.prod-key, product.prod-name

对不起这么长的帖子我很抱歉!我只是想确保我的基地被覆盖了!

3 个答案:

答案 0 :(得分:2)

你想加入你的表格:

from reservation res join order-header oh on res.bill-cust-key = oh.bill-cust-key
join order-item oi on oi.order-num = oh.order-num
and oi.prod-key = res.prod-key
/*   join customer c on c.cust-key = oi.cust-key  old one */
join customer c on c.cust-key = oh.bill-cust-key
join product p on p.prod-key = oi.prod-key

答案 1 :(得分:1)

我发现使用CROSS APPLY(或OUTER APPLY)将输出行与聚合行分开是非常有用的,如果你没有访问权限那么只需要别名的内部查询。

例如,

SELECT 
    customer.cust-key, 
    customer.cust-name, 

    tDetails.prod-key, 
    tDetails.prod-name,
    tDetails.qty-ordered,
    tDetails.qty-reserved

FROM customer

--note that this could be an inner-select table in which you join if not cross-join
CROSS APPLY (
    SELECT
         product.prod-key, 
        prod.prod-name,
        SUM(order-item.qty-ordered) as qty-ordered, 
        SUM(reservation.qty-reserved) as qty-reserved
    FROM reservation
        INNER JOIN order-item ON reservation.prod-key = order-item.product-key
         INNER JOIN product ON reservation.prod-key = product.prod-key
    WHERE
        reservation.bill-cust-key = customer.cut-key
    GROUP BY product.prod-key, prod.prod-name
) tDetails

有很多方法可以解决这个问题,但是你开始以正确的方式说“我想要返回什么记录集”。我喜欢上述内容,因为它可以帮助我直观地了解每个'查询'正在做什么。由CROSS应用标记的内部查询只是按prod订单和预订进行分组,但是在最外层查询中由当前客户进行过滤。

另外,我会继续加入'WHERE'条款。对非主键过滤使用'WHERE'子句(例如cust-name ='Bob')。我发现一个是表连接是有帮助的,'WHERE'子句是一个属性过滤器。

TAKE 2 - 使用内联查询

此方法仍尝试获取具有不同产品的客户列表,然后使用该数据形成外部查询,您可以从中获取聚合。

SELECT 
    customer.cust-key, 
    customer.cust-name, 

    products.prod-key, 
    products.prod-name,

    --aggregate for orders
    (   SELECT SUM(order-item.qty-ordered) 
        FROM order-item 
        WHERE
            order-item.cust-key = customer.cust-key AND
            order-item.prod-key = products.prod-key) AS qty-ordered,

    --aggregate for reservations
    (   SELECT SUM(reservation.qty-reserved)
        FROM reservations
            --join up billingcustomers if they are different from customers here
        WHERE
            reservations.bill-cust-key = customer.cust-key AND
            reservations.prod-key = products.prod-key) AS qty-reserved

FROM customer

    --get a table of distinct products across orders and reservations
    --join products table for name
    CROSS JOIN (
        SELECT DISTINCT order-item.prod-key FROM order-item
        UNION
        SELECT DISTINCT reservation.prod-key FROM reservations
    ) tDistinctProducts
        INNER JOIN products ON products.prod-key = tDistinctProducts.prod-key

TAKE 3 - 派生表

根据一些快速的Google搜索,Progress DB确实支持派生表。这种方法已基本上被CROSS APPLY(或OUTER APPLY)取代,因为您不需要进行分组。但是,如果你的数据库只支持这种方式,那就这样吧。

SELECT 
        customer.cust-key, 
        customer.cust-name, 

    products.prod-key, 
    products.prod-name,

   tOrderItems.SumQtyOrdered,

   tReservations.SumQtyReserved

FROM customer

    --get a table of distinct products across orders and reservations
    --join products table for name
    CROSS JOIN (
        SELECT DISTINCT order-item.prod-key FROM order-item
        UNION
        SELECT DISTINCT reservation.prod-key FROM reservations
    ) tDistinctProducts
        INNER JOIN products ON products.prod-key = tDistinctProducts.prod-key

    --derived table for order-items
    LEFT OUTER JOIN  (   SELECT 
                            order-item.cust-key,
                            order-item.prod-key,
                            SUM(order-item.qty-ordered) AS SumQtyOrdered
                        FROM order-item 
                        GROUP BY 
                            order-item.cust-key,
                            order-item.prod-key) tOrderItems ON
                                    tOrderItems.cust-key = customer.cust-key AND
                                    tOrderItems.prod-key = products.prod-key

    --derived table for reservations
    LEFT OUTER JOIN (   SELECT
                            reservations.bill-cust-key,
                            reservations.prod-key,
                            SUM(reservations.qty-reserved) AS SumQtyReserved
                        FROM reservations
                            --join up billingcustomers if they are different from customers here
                        WHERE
                            reservations.bill-cust-key = customer.cust-key AND
                            reservations.prod-key = products.prod-key) tReservations ON
                                tReservations.bill-cust-key = customer.cust-key AND
                                tReservations.prod-key = products.prod-key

答案 2 :(得分:1)

根据您的原始代码和请求,这是Progress解决方案的起点 -

DEFINE VARIABLE iQtyOrd         AS INTEGER     NO-UNDO.
DEFINE VARIABLE iQtyReserved    AS INTEGER     NO-UNDO.

FOR EACH order-item
    NO-LOCK,

    EACH order-header
        WHERE order-header.order-num = order-item.order-num
        NO-LOCK,

    EACH reservation
        WHERE reservation.prod-key      = order-item.prod-key    AND
              reservation.bill-cust-key = order-header.bill-cust-key
        NO-LOCK,

    EACH product
        WHERE product.prod-key = reservation.prod-key
        NO-LOCK,

    EACH customer
        WHERE customer.cust-key = reservation.bill-cust-key
        NO-LOCK

    BREAK BY customer.cust-key
          BY product.prod-key
          BY product.prod-name
    :

    IF FIRST-OF(customer.cust-key) OR FIRST-OF(product.prod-key) THEN
        ASSIGN
            iQtyOrd = 0
            iQtyReserved = 0
            .

    ASSIGN
        iQtyOrd         = iQtyOrd + reservation.qty-ordered
        iQtyReserved    = iQtyReserved + reservation.qty-reserved
        .

    IF LAST-OF(customer.cust-key) OR LAST-OF(product.prod-key) THEN
        DISPLAY
                customer.cust-key
                customer.cust-name
                product.prod-key
                prod.prod-name
                iQtyOrd
                iQtyReserved
            WITH FRAME f-qty
                DOWN
                .

END.