2016-04-23 107 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