ORACLE 中的动态 where 子句
Dynamic where clause in ORACLE
要求是从 STUDENTS table 中获取结果。
如果将零作为学生 ID 传入,则不需要对学生 ID 进行更多过滤。
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
任何关于如何最好地解决这个问题的建议都会很有帮助。
我认为最简单的方法如下:
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
...
假设您有以下类型:
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
...
要求是从 STUDENTS table 中获取结果。 如果将零作为学生 ID 传入,则不需要对学生 ID 进行更多过滤。
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
任何关于如何最好地解决这个问题的建议都会很有帮助。
我认为最简单的方法如下:
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
...
假设您有以下类型:
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
...