30

これが私のクエリです

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    
                )
    )

ここに私が得ているエラーメッセージがあります..

ここに画像の説明を入力

私は何を間違っていますか???

4

6 に答える 6

39

外部結合されないようにサブクエリをプッシュすることで、それを書き直すことができます。

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 ) 
于 2013-01-28T22:05:24.223 に答える
3

どうやら、Oracle は外部結合の結合条件内でのサブクエリの使用をサポートしていないようです。したがって、サブクエリを取り除く必要があります。

問題は、なぜそれが存在するのかということです。「<=」条件が 2 か所あるため、述語は基本的に「発効日が現在より遅くない最新の発効日より遅くないすべてのレコード」を示します。それが本当に必要な場合は、「発効日が今よりも遅くないすべてのレコード」に単純化できます。つまり、次のようになります。

ON 
    (C.SETID = CO.SETID 
        AND C.CUST_ID = CO.CUST_ID 
        AND CO.effdt <= SYSDATE    
)

出来上がり、サブクエリはありません。

しかし、それは本当にあなたが望んでいることですか、それとも最初の "<=" を単に "=" にすることを意味していましたか? つまり、今より前の最新の発効日を持つレコードを見つけますか? それが本当に必要な場合は、書き直すのがより複雑になります。

于 2013-01-28T21:49:34.627 に答える
1

あなたの質問は既に回答されていますが、特定の日付ではなく列に基づいて最新の EFFDT を取得する必要がある場合は、少し異なる場合があります。これらのケースでは、IMPERFECT オプションが 1 つ、UGLY ソリューションが 1 つしか見つかりませんでした...

不完全なオプション:

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 つ作成する傾向があるため、これはあまり頻繁には発生しません。常にそうであるとは限りません。醜い解決策もあります:

私はまた、1つの醜いオプションを見つけました(しかし、私は実際にそれをお勧めします、そしてそれは問題を解決するので、それを解決策と呼びましょう)、これは次のとおりです:

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 ステートメントに追加します。私が言ったように...それは醜い解決策ですが、解決策です。

私の醜い解決策では、行が後でアプリケーションエンジンまたは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
于 2014-02-28T00:03:24.130 に答える
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    
            )
)
于 2018-12-29T16:53:59.377 に答える