Oracle 中的 MAX() OVER PARTITION BY SQL
MAX() OVER PARTITION BY in Oracle SQL
我正在尝试使用 MAX() OVER PARTITION BY 函数来评估我公司购买的特定零件的最新收据。下面是去年几个部分的信息示例table:
| 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 |
如您所见,第三行和第四行显示了同一部件号的两个不同供应商。
这是我当前的查询:
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
我的 return 集看起来像:
| 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 |
任何人都可以就我做错了什么提供建议吗?看起来它只是替换了最近的日期,而不是只给我我想要的最新的行。
最终,我希望我的 table 看起来像这样。但是,我不知道如何正确使用 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 |
使用window函数ROW_NUMBER() OVER (PARTITION BY receipt_item ORDER BY receipt_date DESC)
为每一行分配一个序号。 receipt_item
最近 receipt_date
的行将被编号为 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
这回答了问题的原始版本。
您的 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';
至少,这 return 是您想要的 return。
我在这里看到了几个问题。第一,将聚合函数 MAX()
用作分析函数(Oracle 将其称为 window 函数)的语法如下所示:
MAX(receipt_date) OVER ( PARTITION BY receipt_item )
(注意括号的位置)。其次,从你想要的结果集中,你实际上并不想要一个 window 函数,你想要聚合。 window(或解析)函数总是 return 其分区中的每一行对应一行;这就是它的工作方式。所以我想你想要的是这个:
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' )
的结果......但也许这就是你想要的?)。
只是路过,但我认为您必须将日期格式化为 'YYYY-MM-DD' 格式,这样它就不会考虑 "time".
我正在尝试使用 MAX() OVER PARTITION BY 函数来评估我公司购买的特定零件的最新收据。下面是去年几个部分的信息示例table:
| 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 |
如您所见,第三行和第四行显示了同一部件号的两个不同供应商。
这是我当前的查询:
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
我的 return 集看起来像:
| 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 |
任何人都可以就我做错了什么提供建议吗?看起来它只是替换了最近的日期,而不是只给我我想要的最新的行。
最终,我希望我的 table 看起来像这样。但是,我不知道如何正确使用 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 |
使用window函数ROW_NUMBER() OVER (PARTITION BY receipt_item ORDER BY receipt_date DESC)
为每一行分配一个序号。 receipt_item
最近 receipt_date
的行将被编号为 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
这回答了问题的原始版本。
您的 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';
至少,这 return 是您想要的 return。
我在这里看到了几个问题。第一,将聚合函数 MAX()
用作分析函数(Oracle 将其称为 window 函数)的语法如下所示:
MAX(receipt_date) OVER ( PARTITION BY receipt_item )
(注意括号的位置)。其次,从你想要的结果集中,你实际上并不想要一个 window 函数,你想要聚合。 window(或解析)函数总是 return 其分区中的每一行对应一行;这就是它的工作方式。所以我想你想要的是这个:
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' )
的结果......但也许这就是你想要的?)。
只是路过,但我认为您必须将日期格式化为 'YYYY-MM-DD' 格式,这样它就不会考虑 "time".