1

我想找到最后一次付款(或者NULL如果不适用)为指定的product_id. 下面是我正在使用的表的表示(简化版)。

+----------+
|Products  |
|----------+
|product_id|
+----------+
+---------------+
|Orders         |
+---------------+
|order_id       |
|order_timestamp|
|order_status   |
+---------------+
+-----------------+
|ProductsOrdersMap|
+-----------------+
|product_id       |
|order_id         |
+-----------------+

在 JOIN、MAX、GROUP BY、LEFT JOIN、多个 INNER JOIN 以获得最大 n-per-group 之后,我仍然无法得到正确的结果。大多数情况下,具有多个订单的产品会返回多行。到目前为止,我得到的最好结果是(我正在搜索特定产品):

product_id  order_id  order_timestamp      order_status
8           NULL      NULL                 NULL
9           NULL      NULL                 NULL
10          NULL      NULL                 NULL
12          NULL      NULL                 NULL
13          NULL      NULL                 NULL
14          11        2013-08-13 07:22:01  finished
15          11        2013-08-13 07:22:01  finished
15          12        2013-08-14 00:00:00  finished
32          11        2013-08-13 07:22:01  finished
83          9         2013-08-13 07:04:02  finished
83          10        2013-08-13 07:11:42  finished

编辑: PP之后。anwser,我最终得到以下查询:

SELECT p.product_id, o.order_id, MAX(order_timestamp) AS order_timestamp, order_status
FROM Products p LEFT JOIN (ProductsOrdersMap m, Orders o)
  ON (p.product_id = m.product_id AND m.order_id = o.order_id)
WHERE p.product_id IN (8,9,10,12,13,14,15,32,83)
GROUP BY p.product_id

哪个返回

product_id  order_id  order_timestamp      order_status
8           NULL      NULL                 NULL
9           NULL      NULL                 NULL
10          NULL      NULL                 NULL
12          NULL      NULL                 NULL
13          NULL      NULL                 NULL
14          11        2013-08-13 07:22:01  finished
15          11        2013-08-13 07:22:01  finished
32          11        2013-08-13 07:22:01  finished
83          9         2013-08-13 07:04:02  finished

乍一看,它似乎是正确的,但只有产品 ID 和时间戳是正确的。比较上面的两个查询,您可以看到,对于产品 15 和 83,order_id是错误的(order_status也可能是错误的)。

4

3 回答 3

2

此查询应返回指定的结果集(这只是桌面检查,未测试)

返回所有 product_id

SELECT p.product_id
     , m.order_d
     , m.order_timestamp
     , m.order_status
  FROM products p
  LEFT
  JOIN ( SELECT kl.product_id
              , MAX(ko.order_timestamp) AS latest_timestamp
           FROM orderproductsmap kl
           JOIN orders ko
             ON ko.order_id = kl.order_id
          GROUP
             BY kl.product_id
       ) l
    ON l.product_id = p.product_id
  LEFT
  JOIN ( SELECT ml.product_id
              , mo.order_id
              , mo.order_timestamp
              , mo.order_status
           FROM orderproductsmap ml
           JOIN orders mo
             ON mo.order_id = ml.order_id
       ) m
    ON m.product_id = l.product_id
   AND m.order_timestamp = l.latest_timestamp
 GROUP
    BY p.product_id

内联视图 " " 为我们提供了每个 " "l的最新 " "。这与内联视图“ ”相连,以获取具有最新时间戳的订单的整行。order_timestampproduct_idm

如果碰巧有多个订单具有相同的最新“ order_timestamp”(即order_timestamp不保证对于给定的订单是唯一的product_id),那么最外面GROUP BY的订单会确保只返回这些订单行中的一个。

如果只需要返回特定的 product_id 值,请在最外层查询中添加 WHERE 子句。为了提高性能,可以在内联视图中重复相同的谓词。

为了只返回 SPECIFIC product_id,我们添加了三个 WHERE 子句:

SELECT p.product_id
     , m.order_d
     , m.order_timestamp
     , m.order_status
  FROM products p
  LEFT
  JOIN ( SELECT kl.product_id
              , MAX(ko.order_timestamp) AS latest_timestamp
           FROM orderproductsmap kl
           JOIN orders ko
             ON ko.order_id = kl.order_id
          WHERE kl.product_id IN (8,9,10,12,13,14,15,32,83)
          GROUP
             BY kl.product_id
       ) l
    ON l.product_id = p.product_id
  LEFT
  JOIN ( SELECT ml.product_id
              , mo.order_id
              , mo.order_timestamp
              , mo.order_status
           FROM orderproductsmap ml
           JOIN orders mo
             ON mo.order_id = ml.order_id
          WHERE ml.product_id IN (8,9,10,12,13,14,15,32,83)
       ) m
    ON m.product_id = l.product_id
   AND m.order_timestamp = l.latest_timestamp
 WHERE p.product_id IN (8,9,10,12,13,14,15,32,83)
 GROUP
    BY p.product_id

只有最外层查询的 WHERE 子句是必需的。添加另外两个只是为了通过限制每个派生表的大小来提高性能。

于 2013-08-13T18:07:54.140 回答
1

    SELECT
        P.product_id
        ,MAX(order_timestamp)
    FROM
        Products P
        ,Orders O
        ,ProductsOrdersMap M
    WHERE
        P.product_id = M.product_id
        AND O.order_id = M.order_id
    GROUP BY
        P.product_id
于 2013-08-13T15:21:21.897 回答
1

退回所有产品,即使是那些没有订单的产品,LEFT JOIN绝对是要走的路。上面@PP 的答案使用“旧式”内部连接,相当于:

SELECT
    P.product_id
    ,MAX(order_timestamp)
FROM Products P
INNER JOIN ProductsOrdersMap M ON P.product_id = M.product_id
INNER JOIN Orders O ON O.order_id = M.order_id
GROUP BY
    P.product_id

从这种语法开始,更容易获得LEFT JOIN- 只需替换INNERLEFT

SELECT
    P.product_id
    ,MAX(order_timestamp)
FROM Products P
LEFT JOIN ProductsOrdersMap M ON P.product_id = M.product_id
LEFT JOIN Orders O ON O.order_id = M.order_id
GROUP BY
    P.product_id

附录:Renato 需要的不仅仅是将另一个答案改写为 a LEFT JOIN,因为order_id并且order_status必须与最大时间戳一起出现。最简单的方法是从产品 ID 和订单 ID 的列表开始,其中订单的最大时间戳为order_id

SELECT
  p2.product_id,
  o2.order_id
FROM Products p2
INNER JOIN ProductsOrdersMap m ON p2.product_id = m.product_id
INNER JOIN Orders o2 ON m.order_id = o2.order_id
WHERE (o2.order_id, o2.order_timestamp) IN (
  SELECT order_id, MAX(order_timestamp)
  FROM Orders
  GROUP BY order_id)

然后,不要使用ProductsOrdersMap将产品解析为订单,而是使用上面查询的结果:

SELECT
  p.product_id,
  o.order_id,
  o.TS,
  o.order_status
FROM Products p
LEFT JOIN (
  SELECT
    p2.product_id,
    o2.order_id
  FROM Products p2
  INNER JOIN ProductsOrdersMap m ON p2.product_id = m.product_id
  INNER JOIN Orders o2 ON m.order_id = o2.order_id
  WHERE (o2.order_id, o2.order_timestamp) IN (
    SELECT order_id, MAX(order_timestamp)
    FROM Orders
    GROUP BY order_id)
  ) MaxTS ON p.product_id = MaxTS.product_id
LEFT JOIN Orders o ON MaxTS.order_id = o.order_id
于 2013-08-13T16:19:42.813 回答