MAX()在Oracle SQL中超过PARTITION BY

时间:2018-03-22 18:39:41

标签: sql oracle window-functions

我正在尝试使用MAX()OVER PARTITION BY函数来评估我公司购买的特定零件的最新收据。以下是去年几个部分的信息示例表:

| VEND_NUM | VEND_NAME    | RECEIPT_NUM | RECEIPT_ITEM | RECEIPT_DATE |
|----------|--------------|-------------|----------|--------------|
| 100      | SmallTech    | 2001        | 5844HAJ  | 11/22/2017   |
| 100      | SmallTech    | 3188        | 5521LRO  | 12/31/2017   |
| 200      | RealSolution | 5109        | 8715JUI  | 05/01/2017   |
| 100      | SmallTech    | 3232        | 8715JUI  | 11/01/2017   |
| 200      | RealSolution | 2101        | 4715TEN  | 01/01/2017   |

如您所见,第三和第四行显示了SAME部件号的两个不同供应商。

这是我当前的查询:

WITH

-- various other subqueries above...

    AllData AS
    (
        SELECT VEND_NUM, VEND_NAME, RECEIPT_NUM, RECEIPT_ITEM, RECEIPT_DATE
        FROM tblVend
            INNER JOIN tblReceipt ON VEND_NUM = RECEIPT_VEND_NUM
        WHERE
            VEND_NUM = '100' OR VEND_NUM = '200' AND RECEIPT_DATE >= '01-Jan-2017'
    ),

    SELECT MAX(RECEIPT_DATE) OVER PARTITION BY(RECEIPT_ITEM) AS "Recent Date", RECEIPT_ITEM
    FROM AllData

我的回归设置如下:

| Recent Date | RECEIPT_ITEM |
|-------------|--------------|
| 11/22/2017  | 5844HAJ      |
| 12/31/2017  | 5521LRO      |
| 11/01/2017  | 8715JUI      |
| 11/01/2017  | 8715JUI      |
| 01/01/2017  | 4715TEN      |

但是,它应该是这样的:

| Recent Date | RECEIPT_ITEM |
|-------------|--------------|
| 11/22/2017  | 5844HAJ      |
| 12/31/2017  | 5521LRO      |
| 11/01/2017  | 8715JUI      |
| 01/01/2017  | 4715TEN      |

有人可以就我做错了什么提出建议吗?看起来它只是简单地取代了最近的日期,而不仅仅是给了我想要的最新日期。

最终,我希望我的桌子看起来像这样。但是,我不知道如何正确使用MAX()或MAX()OVER PARTITION BY()函数来实现这个目的:

| VEND_NUM | VEND_NAME    | RECEIPT_NUM | RECEIPT_ITEM | RECEIPT_DATE |
|----------|--------------|-------------|----------|--------------|
| 100      | SmallTech    | 2001        | 5844HAJ  | 11/22/2017   |
| 100      | SmallTech    | 3188        | 5521LRO  | 12/31/2017   |
| 100      | SmallTech    | 3232        | 8715JUI  | 11/01/2017   |
| 200      | RealSolution | 2101        | 4715TEN  | 01/01/2017   |

4 个答案:

答案 0 :(得分:2)

使用窗口函数ROW_NUMBER() OVER (PARTITION BY receipt_item ORDER BY receipt_date DESC)为每一行分配序列号。 receipt_date的最新receipt_item行将编号为1。

WITH
-- various other subqueries above...

    AllData AS
    (
        SELECT VEND_NUM, VEND_NAME, RECEIPT_NUM, RECEIPT_ITEM, RECEIPT_DATE,
        ROW_NUMBER() OVER (PARTITION BY RECEIPT_ITEM ORDER BY RECEIPT_DATE DESC ) AS RN
        FROM tblVend
            INNER JOIN tblReceipt ON VEND_NUM = RECEIPT_VEND_NUM
        WHERE
            VEND_NUM IN ( '100','200')  AND RECEIPT_DATE >= '01-Jan-2017'
    )
   SELECT VEND_NUM, VEND_NAME, RECEIPT_NUM, RECEIPT_ITEM, RECEIPT_DATE
   FROM AllData WHERE RN = 1

答案 1 :(得分:1)

我在这里看到了几个问题。一,使用聚合函数MAX()作为分析函数的语法(这是Oracle帮助调用窗口函数的函数)如下所示:

MAX(receipt_date) OVER ( PARTITION BY receipt_item )

(注意括号的位置)。其次,从您想要的结果集中,您实际上并不想要一个窗口函数,而是想要聚合。窗口(或分析)函数将始终为其分区中的每一行返回一行;这就是它的工作方式。所以我认为你想要的是:

WITH
-- various other subqueries above...
AllData AS
(
    SELECT VEND_NUM, VEND_NAME, RECEIPT_NUM, RECEIPT_ITEM, RECEIPT_DATE
      FROM tblVend
     INNER JOIN tblReceipt ON VEND_NUM = RECEIPT_VEND_NUM
     WHERE ( VEND_NUM = '100' OR VEND_NUM = '200' ) AND RECEIPT_DATE >= DATE'2017-01-01'
)
SELECT VEND_NUM, VEND_NAME, RECEIPT_NUM, RECEIPT_ITEM, MAX(RECEIPT_DATE)
  FROM AllData
 GROUP BY VEND_NUM, VEND_NAME, RECEIPT_NUM, RECEIPT_ITEM;

现在我对上面做了一些小改动,例如围绕OR条件括起括号(使用IN ('100','200')可能更好),因为AND优先于OR (所以你的查询会得到VEND_NUM = '100' OR ( VEND_NUM = '200' RECEIPT_DATE >= DATE'2017-01-01' )的结果......但也许这就是你想要的?)。

答案 2 :(得分:1)

只是路过,但我认为您必须将日期格式化为“ YYYY-MM-DD”格式,这样才不会考虑“时间”。

答案 3 :(得分:0)

这是对问题的原始版本的回答。

您的where子句应该如下所示:

 WHERE VEND_NUM IN ('100', '200') AND RECEIPT_DATE >= DATE '2017-01-01'

很有可能你想要的只是:

SELECT DISTINCT RECEIPT_DATE, RECEIPT_ITEM
FROM tblVend INNER JOIN
     tblReceipt
     ON VEND_NUM = RECEIPT_VEND_NUM
WHERE VEND_NUM IN ('100', '200') AND RECEIPT_DATE >= DATE '2017-01-01';

至少,这会返回您想要返回的内容。