ORACLE中的动态where子句

时间:2016-04-23 12:01:47

标签: oracle plsql where-clause

要求是从STUDENTS表中获取结果。 如果作为学生ID传入零,则不再需要对studentid进行过滤。

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转换为STRING,然后进行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

任何关于如何最好地解决这个问题的指针都将是一个很大的帮助。

2 个答案:

答案 0 :(得分: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
      ... 

答案 1 :(得分: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
      ...