[英]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.