这是我的查询
SELECT
COUNT(C.SETID)
FROM
MYCUSTOMER C
LEFT OUTER JOIN MYCUSTOPTION CO
ON
(C.SETID = CO.SETID
AND C.CUST_ID = CO.CUST_ID
AND CO.effdt = (
SELECT MAX(COI.EFFDT)
FROM MYCUSTOPTION COI
WHERE
COI.SETID = CO.SETID
AND COI.CUST_ID = CO.CUST_ID
AND COI.EFFDT <=SYSDATE
)
)
这是我收到的错误消息..
我做错了什么???
答案 0 :(得分:32)
你可以通过推送子查询来重写它,使其不在外部加入:
select Count(C.setid)
from mycustomer C
left outer join (select *
from mycustoption co
where co.effdt <= (select Max(COI.effdt)
from mycustoption COI
where COI.setid = co.setid
and COI.cust_id = co.cust_id
and COI.effdt <= sysdate)) co
on ( C.setid = CO.setid
and C.cust_id = CO.cust_id )
答案 1 :(得分:3)
好吧,Oracle显然不支持在连接条件中使用子查询进行外连接。所以你需要摆脱子查询。
问题是,它为什么会存在?您在两个地方都有“&lt; =”条件,因此谓词基本上表示“所有记录的生效日期不迟于不迟于现在的最新生效日期”。如果这是你真正想要的,你可以简化为“所有生效日期不晚于现在的记录”,即:
ON
(C.SETID = CO.SETID
AND C.CUST_ID = CO.CUST_ID
AND CO.effdt <= SYSDATE
)
Voila,没有子查询。
但这真的是你想要的,还是你的意思是第一次“&lt; =”只是“=” - 即在现在之前找到最近生效日期的记录?如果那是你真正想要的,那么重写会更复杂。
答案 2 :(得分:1)
您的问题已经得到解答,但有些人可能会略有不同,他们需要根据专栏而不是固定日期获取最新的EFFDT。对于这些情况,我只发现了一个IMPERFECT选项和一个UGLY解决方案......
不完美的选项:
SELECT ...
FROM MYTABLE N, CUST_OPT C
WHERE etc...
AND C.SETID (+) = N.SETID
AND C.CUST_ID (+) = N.CUST_ID
AND NVL(C.EFFDT,TO_DATE('01011900','DDMMYYYY')) = NVL((SELECT MAX(EFFDT)
FROM CUST_OPT SC
WHERE SC.SETID = C.SETID
AND SC.CUST_ID = C.CUST_ID
AND SC.EFFDT <= N.ISSUE_DT)
,TO_DATE('01011900','DDMMYYYY'))
这是一个不完美的选项,因为如果CUST_OPT表具有将来的日期,但没有当前(&lt; = N.ISSUE_DT)日期,则外部联接将不起作用,并且不会返回任何行。一般来说PeopleSoft条款(是的,我在那里看到了你的SETID + EFFDT!;-D)这种情况不会经常发生,因为人们倾向于创建一个01/01/1900 EFFDT以使第一个值自“永远”起有效,但是情况并非总是如此;我们也有一个丑陋的解决方案:
我还找到了一个UGLY选项(但我实际上推荐它,它解决了问题,所以我们称之为解决方案),这就是:
SELECT n.field1, n.field2,
CASE WHEN NVL(c.EFFDT,n.ISSUE_DT-1)<=n.ISSUE_DT THEN c.field1 ELSE NULL END,
CASE WHEN NVL(c.EFFDT,n.ISSUE_DT-1)<=n.ISSUE_DT THEN c.field2 ELSE NULL END
FROM MYTABLE N, CUST_OPT C
WHERE etc...
AND C.SETID (+) = N.SETID
AND C.CUST_ID (+) = N.CUST_ID
AND NVL(C.EFFDT,TO_DATE('01011900','DDMMYYYY')) = NVL((SELECT MAX(EFFDT)
FROM CUST_OPT SC
WHERE SC.SETID = C.SETID
AND SC.CUST_ID = C.CUST_ID
AND SC.EFFDT <= N.ISSUE_DT)
,NVL( (SELECT MIN(EFFDT)
FROM CUST_OPT SC
WHERE SC.SETID = C.SETID
AND SC.CUST_ID = C.CUST_ID
AND SC.EFFDT >= N.ISSUE_DT)
,TO_DATE('01011900','DDMMYYYY')
)
)
此选项将返回必须忽略的FUTURE行!因此,我们在SELECT语句中添加IGNORE返回值的条件(如果它们不是要检索的话)。 就像我说的......这是一个UGLY解决方案,但它是一个解决方案。
对于我丑陋的解决方案,如果稍后将在Application Engine或PL / SQL或其他任何行中处理这些行;您可以,而不是为每列添加CASE语句,只需添加一个新列,该列将告诉您提取“不正确”数据并忽略代码中的字段,基于此列,如下所示:
CASE WHEN NVL(c.EFFDT,n.ISSUE_DT-1)<=n.ISSUE_DT THEN 'N' ELSE 'Y' END AS IGNORE_CUST_OP_COLS
答案 3 :(得分:1)
我今天也遇到了这个问题,并提出了
SELECT
COUNT(C.SETID)
FROM
MYCUSTOMER C
LEFT OUTER JOIN MYCUSTOPTION CO
ON
(C.SETID = CO.SETID
AND C.CUST_ID = CO.CUST_ID
AND CO.effdt IN (
SELECT MAX(COI.EFFDT)
FROM MYCUSTOPTION COI
WHERE
COI.SETID = CO.SETID
AND COI.CUST_ID = CO.CUST_ID
AND COI.EFFDT <=SYSDATE
)
)
答案 4 :(得分:1)
选项1
select COUNT(C.SETID)
from MYCUSTOMER C
left outer join (
select *
from MYCUSTOPTION CO
on CO.effdt = (
select MAX(COI.EFFDT)
from MYCUSTOPTION COI
where COI.SETID = CO.SETID
and COI.CUST_ID = CO.CUST_ID
and COI.EFFDT <= SYSDATE
)
) CO
on C.SETID = CO.SETID
and C.CUST_ID = CO.CUST_ID;
选项2
select COUNT(C.SETID)
from MYCUSTOMER C
left outer join MYCUSTOPTION CO
on C.SETID = CO.SETID
and C.CUST_ID = CO.CUST_ID
where nvl(CO.effdt, to_date('19000101', 'YYYYMMDD')) = NVL((
select MAX(COI.EFFDT)
from MYCUSTOPTION COI
where COI.SETID = CO.SETID
and COI.CUST_ID = CO.CUST_ID
and COI.EFFDT <= C.SINCE_DT
), to_date('19000101', 'YYYYMMDD'))
Option1正常工作,只要您要查询“ today”(今天)(COI.EFFDT <= SYSDATE)时的MYCUSTOPTION表,在这种情况下,这就是您的要求。但是,如果您要从“ C.SINCE_DT”开始查询MYCUSTOPTION,将无法正常工作
Option2看起来有点复杂,但是效果更好,允许您在sysdate或任何其他日期字段之间进行切换,而无需更改其他任何内容(COI.EFFDT <= C.SINCE_DT)
答案 5 :(得分:0)
尝试了其他答案中的LEFT OUTER JOIN
后,它可以工作,但速度确实很慢...
我个人最好的解决方案是创建与您需要的最新记录相关的VIEW,并对其进行左联接。
CREATE VIEW VIEW_SOF_TOF as
SELECT SOF."FIELDA1", TOF."FIELDB1", TOF."FIELDB2", ...
FROM SOF, TOF
WHERE FIELDA1 (+) = FIELDB1
AND ( FIELDB2 = (SELECT MAX(FIELDB2) FROM TOF WHERE FIELDA1 = FIELDB1)
OR FIELDB2 IS NULL)