我希望根据存储过程中收到的INPUT在WHERE子句中使用单独的列。
如果TYPE_DEFINITION ='SUP',则使用SUPPLIER列
如果TYPE_DEFINITION ='CAT',则使用CATEGORY列
我知道我可以使用SELECT
语句写两个单独的CASE
,但这将是非常愚蠢和多余的。任何更干净的方式吗?
CREATE OR REPLACE PROCEDURE SG.STORED_PROCEDURE (
TYPE_DEFINITION IN VARCHAR2,
VALUE IN VARCHAR2,
STORELIST IN VARCHAR2)
AS
BEGIN
SELECT O.ORGNUMBER,
S.SKU,
FROM SKU S JOIN ORG O ON S.ORGID = O.ORGID
WHERE
AND O.ORGNUMBER IN (STORELIST)
AND (CASE TYPE_DEFINITION
WHEN 'SUP' THEN S.SUPPLIER = VALUE
ELSE S.CATEGORY = VALUE
END);
END;
/
答案 0 :(得分:1)
您需要在程序中使用dynamic sql。
这样的事情:
CREATE OR REPLACE PROCEDURE SG.STORE_PROC (
TYPE_DEFINITION IN VARCHAR2,
VALUE IN VARCHAR2,
STORELIST IN VARCHAR2)
AS
TYPE EmpCurTyp IS REF CURSOR;
v_emp_cursor EmpCurTyp;
v_stmt_str VARCHAR2(200);
v_orgnumber VARCHAR2(200);
v_sku VARCHAR2(200);
BEGIN
v_stmt_str := 'SELECT O.ORGNUMBER, S.SKU,FROM SKU S JOIN ORG O ON S.ORGID = O.ORGID ';
if type_definition = 'SUP' then
v_stmt_str := v_stmt_str || 'WHERE s.supplier = :v';
else
v_stmt_str := v_stmt_str || 'WHERE s.category = :v';
end if;
-- Open cursor & specify bind variable in USING clause:
OPEN v_emp_cursor FOR v_stmt_str USING value;
-- Fetch rows from result set one at a time:
LOOP
FETCH v_emp_cursor INTO v_orgnumber, v_sku;
-- you can do something here with your values
EXIT WHEN v_emp_cursor%NOTFOUND;
END LOOP;
-- Close cursor:
CLOSE v_emp_cursor;
END;
/
答案 1 :(得分:1)
您的代码非常接近。 CASE
THEN
必须返回表达式,而不是条件。但是CASE
可以用作条件的一部分,只需移动= VALUE
到外面。
改变这个:
AND (CASE TYPE_DEFINITION
WHEN 'SUP' THEN S.SUPPLIER = VALUE
ELSE S.CATEGORY = VALUE
END);
To This:
AND VALUE = (CASE TYPE_DEFINITION
WHEN 'SUP' THEN S.SUPPLIER
ELSE S.CATEGORY
END);
您的代码很有意义。这种限制可能是甲骨文未完全支持布尔人的结果。
<强>更新强>
如果遇到性能问题,可能需要使用动态SQL或确保静态SQL正确使用FILTER
操作。当Oracle构建执行计划时,它可以使用绑定变量(如常量),并根据输入选择不同的计划。正如Ben指出的那样,这些FILTER
操作并不总是完美有效,如果您使用这样的简化条件,有时可能会有所帮助:
(TYPE_DEFINITION = 'SUP' AND S.SUPPLIER = VALUE)
OR
((TYPE_DEFINITION <> 'SUP' OR TYPE_DEFINITION IS NULL) AND S.CATEGORY = VALUE)