ここに私の質問があります
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
)
)
ここに私が得ているエラーメッセージがあります。
私は何を間違えていますか???
サブクエリをプッシュして、外部結合されないように書き換えることができます。
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 )
まあ、Oracleは明らかに外部結合の結合条件内でのサブクエリの使用をサポートしていません。したがって、サブクエリを削除する必要があります。
問題は、なぜそこにあるのですか? 「<=」条件は2か所にあるため、述部は基本的に「発効日が現在よりも遅い最新の発効日よりも遅いすべてのレコード」と言います。それが本当に必要なものである場合は、「発効日が今より遅くないすべてのレコード」、つまり次のように単純化できます。
ON
(C.SETID = CO.SETID
AND C.CUST_ID = CO.CUST_ID
AND CO.effdt <= SYSDATE
)
出来上がり、サブクエリなし。
しかし、それは本当にあなたが望むものですか、それとも最初の「<=」が「=」になることを意味しましたか?つまり、今より前の最新の発効日を持つレコードを見つけますか?それが本当に必要なものである場合、書き換えるのはより複雑になります。
私も今日この問題に直面しました
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
)
)
あなたの質問はすでに回答されていますが、誰かが、固定された日付ではなく、列に基づいて最新のEFFDTを取得する必要がある場合とはわずかに異なる場合があります。それらの場合、1つのIMPERFECTオプションと1つの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テーブルに将来の日付があるが、現在の(<= N.ISSUE_DT)日付がない場合、外部結合が機能せず、行が返されないため、これは不完全なオプションです。 PeopleSoftの一般的な用語(そうですね、SETID + EFFDTを見ました!;-D)これは、人々が「永遠に」以来、最初の値を有効にするために1900年1月1日のEFFDTを作成する傾向があるため、あまり起こりませんが、常にそうとは限りません。い解決策もあります:
また、1つの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')
)
)
このオプションは、無視する必要のある将来の行を返します!したがって、返される値が取得されることを意図していない場合、返される値を無視する条件をSELECTステートメントに追加します。私が言ったように...それはい解決策ですが、それは解決策です。
私のいソリューションでは、行が後で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