web-dev-qa-db-ja.com

Oracle SQLのMAX()OVER PARTITION BY

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   |

ご覧のとおり、3行目と4行目は、同じ部品番号の2つの異なるベンダーを示しています。

これが私の現在のクエリです:

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   |
1
wundermahn

ウィンドウ関数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
3
kc2018

ここにいくつかの問題があります。 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;
_

ORANDよりも優先されるため(IN ('100','200')を使用する方が良い場合があります)、OR条件を括弧で囲むなど、上記にいくつかの小さな変更を加えました(したがって、クエリはVEND_NUM = '100' OR ( VEND_NUM = '200' RECEIPT_DATE >= DATE'2017-01-01' ) ...しかし、多分それはあなたが望んでいたことですか?).

1
David Faber

これは、質問の元のバージョンに答えます。

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';

少なくとも、これはあなたが返したいものを返します。

0
Gordon Linoff