2016-04-23 93 views
1

需求是從STUDENTS表中提取結果。 如果傳入零作爲學號,則不需要對學生進行更多篩選。ORACLE中的動態where子句

PROCEDURE getResults (  
    inStudentId  IN NUMBER, 
    inSectionId  IN NUMBER, 
    inRowLimit  IN NUMBER, 
    outResultsData OUT gphResultsData 
) AS 
    stStudentId VARCHAR2(50) := ''; 
    BEGIN 
    outResultsData := gphResultsData(); 
    IF inStudentId = '0' THEN 
     stStudentId := '%'; 
    ELSE 
     stStudentId := TO_CHAR(inStudentId); 
    END IF; 

    FOR rResults IN (
     SELECT 
     RESULTS.STUDENT_ID, 
     RESULTS.STUDENT_NAME 
     FROM 
     RESULTS 
     WHERE 
     RESULTS.STUDENT_ID LIKE stStudentId AND -- not a good idea 
     RESULTS.SECTION_ID = inSectionId AND 
     ROWNUM <= inRowLimit 
    ) LOOP 
     outResultsData.extend; 
     outResultsData(outResultsData.last).studentId := rResults.STUDENT_ID; 
     outResultsData(outResultsData.last).studentName := rResults.STUDENT_NAME; 
    END LOOP; 

    EXCEPTION 
    WHEN others THEN 
     ... 

我已經提出了上述的解決方案 - 這是絕對不理想,因爲

inStudentId使用TO_CHAR轉換成字符串,然後進行LIKE

我想更好的辦法是動態生成並執行where子句。那就是 -

如果inStudentId = 0,

SELECT 
    RESULTS.STUDENT_ID, 
    RESULTS.STUDENT_NAME 
FROM 
    RESULTS 
WHERE 
    RESULTS.SECTION_ID = inSectionId AND 
    ROWNUM <= inRowLimit 

如果inStudentId不爲零,

SELECT 
    RESULTS.STUDENT_ID, 
    RESULTS.STUDENT_NAME 
    FROM 
    RESULTS 
    WHERE 
    RESULTS.STUDENT_ID = inStudentId AND 
    RESULTS.SECTION_ID = inSectionId AND 
    ROWNUM <= inRowLimit 

如何以最佳方式解決這一問題將是一個很大的任何指針幫幫我。

+0

如果你想要,你可以把條件放在'WHERE'子句中:'RESULTS.SECTION_ID = DECODE(inSecti onId,0,RESULTS.SECTION_ID,inSectionId)' – Glenn

+0

當寫出完整的邏輯條件不會變得太複雜時,最好避免DECODE;那麼代碼「爲自己說話」,更容易維護和修改等等,就像在CarloCe的解決方案中一樣。 – mathguy

+0

@OriginalPoster:你需要在PL/SQL中做到這一點嗎?這看起來像一個普通SQL的工作。還是有額外的處理,你只是向我們展示了你遇到麻煩的部分? – mathguy

回答

0

假設你有兩類:

CREATE TYPE gphResult IS OBJECT(
    student_id INT, 
    student_name VARCHAR2(50) 
); 
/

CREATE TYPE gphResultsData IS TABLE OF gphResult; 
/

然後你可以使用BULK COLLECT INTO這樣避免了循環:

PROCEDURE getResults (  
    inStudentId  IN NUMBER, 
    inSectionId  IN NUMBER, 
    inRowLimit  IN NUMBER, 
    outResultsData OUT gphResultsData 
) AS 
    stStudentId VARCHAR2(50) := ''; 
    BEGIN 
    SELECT gphResult(STUDENT_ID, STUDENT_NAME) 
    BULK COLLECT INTO outResultsData 
    FROM RESULTS 
    WHERE (inStudentId = 0 OR student_id = inStudentId) 
    AND SECTION_ID = inSectionId 
    AND ROWNUM  <= inRowLimit; 
    EXCEPTION 
    WHEN others THEN 
     ... 
+0

隨機匿名downvoter照顧評論? – MT0

1

我認爲這樣做最簡單的方法是:

PROCEDURE getResults (  
    inStudentId  IN NUMBER, 
    inSectionId  IN NUMBER, 
    inRowLimit  IN NUMBER, 
    outResultsData OUT gphResultsData 
) AS 
    BEGIN 
    outResultsData := gphResultsData(); 
    FOR rResults IN (
     SELECT 
     RESULTS.STUDENT_ID, 
     RESULTS.STUDENT_NAME 
     FROM 
     RESULTS 
     WHERE 
     (RESULTS.STUDENT_ID = inStudentId OR inStudentId = 0) AND 
     RESULTS.SECTION_ID = inSectionId AND 
     ROWNUM <= inRowLimit 
    ) LOOP 
     outResultsData.extend; 
     outResultsData(outResultsData.last).studentId := rResults.STUDENT_ID; 
     outResultsData(outResultsData.last).studentName := rResults.STUDENT_NAME; 
    END LOOP; 

    EXCEPTION 
    WHEN others THEN 
     ... 
+0

或者,甚至更簡單,'WHERE inStudentId IN(0,RESULTS.STUDENT_ID)AND'(etc.) – mathguy