[英]Equivalent of SQL Server's “TOP 1” in Oracle (without using rownum or row_number())
我有一個CONTRACTINFO
表,該表存儲合同的折扣代碼(該代碼可以不時更改,具體取決於合同的類型或期限)。
CREATE TABLE CONTRACTINFO
(
ID CHAR(8),
BASERECORD CHAR(1),
DATE CHAR(8),
DISCOUNTCODE CHAR(1)
)
每個月,我們需要根據付款paymentdate
和discountcode
計算客戶必須支付的費用。
CREATE TABLE PAYMENT
(
CONTRACTID CHAR(8),
TIME NUMBER(12),
PAYMENTDATE CHAR(8)
)
折扣代碼是通過從CONTRACTINFO
表中獲取date
< paymentdate
的最后一條記錄來確定的。
我創建了一個簡單的示例來顯示所需的結果(以黃色顯示)。
在SQL Server中,我可以使用下面的相關子查詢輕松實現此目的:
SELECT
PA.*,
(SELECT TOP 1 DISCOUNTCODE
FROM CONTRACTINFO
WHERE ID = PA.CONTRACTID
AND DATE < PA.PAYMENTDATE
ORDER BY DATE DESC) AS DISCOUNTCODE
FROM
PAYMENT PA
INNER JOIN
CONTRACTINFO CI ON PA.CONTRACTID = CI.ID
WHERE
CI.BASERECORD = 1 'ALWAYS GET INFORMATION FROM THE BASE RECORD
但是在Oracle SQL中我不能,因為它沒有top 1函數。
我也不能使用rownum或row_number,因為Oracle不允許我這樣將主查詢列的值傳遞給嵌套子查詢。 (以下代碼將生成“未找到列PA.PAYMENTDATE”錯誤)
SELECT
PA.*,
(
SELECT DISCOUNTCODE FROM
(SELECT * FROM CONTRACTINFO WHERE ID = PA.CONTRACTID AND DATE < PA.PAYMENTDATE ORDER BY DATE DESC)
WHERE ROWNUM = 1
)
AS DISCOUNTCODE
FROM PAYMENT PA
INNER JOIN CONTRACTINFO CI
ON PA.CONTRACTID = CI.ID
WHERE CI.BASERECORD = 1 'ALWAYS GET INFORMATION FROM THE BASE RECORD
如您所指出的,Oracle不支持TOP 1
。 您可以在維護關聯子查詢的同時在Oracle中進行重寫,但是最好的選擇可能是刪除該子查詢,而只需使用已經進行的聯接即可處理邏輯:
WITH cte AS (
SELECT
PA.*,
COALESCE(CI.DISCOUNTCODE, 'NA') AS DISCOUNTCODE,
ROW_NUMBER() OVER (PARTITION BY CI.ID ORDER BY CI.DATE DESC) rn
FROM PAYMENT PA
LEFT JOIN CONTRACTINFO CI
ON PA.CONTRACTID = CI.ID AND
CI.DATE < PA.PAYMENTDATE
WHERE
CI.BASERECORD = 1
)
SELECT CONTRACTID, TIME, PAYMENTDATE, DISCOUNTCODE
FROM cte
WHERE rn = 1;
Oracle fetch first
而不是top n
,因此等效項為:
select pa.*
, ( select discountcode
from contractinfo
where id = pa.contractid
and contractdate < pa.paymentdate
order by contractdate desc fetch first row only ) as discountcode
from payment pa
join contractinfo ci
on pa.contractid = ci.id
where ci.baserecord = 1;
我必須將DATE
重命名為CONTRACTDATE
因為DATE
是SQL關鍵字。 另外,盡管為ANSI完整性提供了char
類型,但通常不建議使用它,因為空白填充是一項非常無用的功能,會浪費空間並導致錯誤。
我可能會從以下內容開始:
create table contracts
( id integer constraint contract_pk primary key
, baserecord integer not null
, contractdate date not null
, discountcode varchar2(1) );
create table payments
( contractid references contracts
, paymentseq number(12)
, paymentdate date default on null sysdate );
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.