web-dev-qa-db-ja.com

条件に基づいて結合クエリから返された最初の行を選択します

PRODUCTとMANUFACTURERの2つのテーブルがあります

表1:PRODUCT、列:PRODUCT_ID、PRODUCT_NAME

表2:MANUFACTURER、列:PRODUCT_ID、MANF_ID、ITEM_NO、DEFAULT_MANF

MANUFACTURERテーブルから製品のデフォルトの製造を選択する必要があります。デフォルトのメーカーが利用できない場合、MANUFACTURERテーブルからITEM_NOでメーカーを選択します。

私はこれについてのクエリを以下のように書いています:

SELECT p.PRODUCT_ID, p.PRODUCT_NAME, m.MANF_ID, m.ITEM_NO, m.DEFAULT_MANF 
FROM PRODUCT p 
INNER JOIN MANUFACTURER m on p.PRODUCT_ID = m.PRODUCT_ID
WHERE p.PRODUCT_ID = 'PROD001' 
AND m.MANF_ID = (SELECT TOP 1 MANF_ID FROM MANUFACTURER man WHERE man.PRODUCT_ID = p.PRODUCT_ID and coalesce(man.DEFAULT_MANF, 'N') = 'Y' ORDER BY man.DEFAULT_MANF, man.MANF_ID )

このクエリはSQL Serverでは期待どおりに機能しますが、Oracleではクエリで「TOP」を使用しているため機能しません。

SQL ServerとOracleの両方で機能するようにクエリを変更する方法はありますか?

1
jos.mathew123

Oracleのバージョンが12以上の場合、FETCH FIRST n ROWS ONLY(doc link) を使用できます。

SELECT p.PRODUCT_ID, p.PRODUCT_NAME, m.MANF_ID, m.ITEM_NO, m.DEFAULT_MANF 
FROM PRODUCT p 
INNER JOIN MANUFACTURER m on p.PRODUCT_ID = m.PRODUCT_ID
WHERE p.PRODUCT_ID = 'PROD001' 
AND m.MANF_ID = (SELECT MANF_ID FROM MANUFACTURER man WHERE man.PRODUCT_ID = p.PRODUCT_ID and coalesce(man.DEFAULT_MANF, 'N') = 'Y' ORDER BY man.DEFAULT_MANF, man.MANF_ID FETCH FIRST 1 ROWS ONLY)

Oracle 11以前を使用している場合は、代わりにrownum=1を使用する必要があります。

スキーマが適切に設計されていれば、製品のデフォルトのメーカーは1つしかなく、サブクエリは必要ないことを付け加えます。

ただし、実際に質問に答えるために、row_numberを悪用することができます。

SELECT p.PRODUCT_ID, p.PRODUCT_NAME, m.MANF_ID, m.ITEM_NO, m.DEFAULT_MANF 
FROM PRODUCT p 
INNER JOIN MANUFACTURER m on p.PRODUCT_ID = m.PRODUCT_ID
WHERE p.PRODUCT_ID = 'PROD001' 
AND m.MANF_ID = (  
    SELECT MANF_ID FROM (
        SELECT MANF_ID, ROW_NUMBER() OVER (ORDER BY man.DEFAULT_MANF, man.MANF_ID) as RN  
        FROM MANUFACTURER man 
        WHERE man.PRODUCT_ID = p.PRODUCT_ID 
        and coalesce(man.DEFAULT_MANF, 'N') = 'Y'
    ) HACK
    WHERE RN=1
);
1
Philᵀᴹ