case-when oracle sql 的动态评估
dynamic evaluation of case-when oracle sql
我想知道是否可以在 Oracle SQL 中动态评估 select
语句中的 case 语句。以下面伪sql代码为例:
WITH temp AS (
SELECT
'WHEN ' || when_col || ' THEN ''' || then_value || '''' as case_logic
FROM some_table
)
SELECT
case
{temp.case_logic} -- EVALUATE THIS FOR ALL ROWS IN TEMP DURING RUNTIME
else 'NA'
end as case_when,
table2.*
FROM table2;
我尝试用占位符实现上述内容,如下所示:
DECLARE
case_when_logic VARCHAR2(4000 byte);
plsql_block VARCHAR2(4000 byte);
TYPE case_when_logic_tbl_type IS TABLE OF VARCHAR2(1000 BYTE);
case_when_logic_tbl case_when_logic_tbl_type;
BEGIN
case_when_logic := q'[SELECT 'WHEN ' | | when_condition_col | | ' THEN ''' | | then_condition_col | | '''' as case_when FROM some_table]';
execute immediate case_when_logic BULK COLLECT INTO case_when_logic_tbl;
plsql_block := q'[SELECT CASE :case_when
ELSE 'some other value'
END case_when_col,
table2.*
FROM table2]';
EXECUTE IMMEDIATE plsql_block USING case_when_logic_tbl;
END;
/
但不幸的是,这会引发错误:
PLS-00457: expressions have to be of SQL types
有没有办法做到这一点?请提供代码示例,因为我没有看到类似的解决方案。
execute immediate 中的 USING
子句采用位置表示法 (docs). So you can't pass a associative array. And you can only pass valid bind variables (explained here) 中的绑定变量。没有 table 名称、条款等
您可以连接 select 语句并执行如下操作:
DECLARE
case_when_logic VARCHAR2(4000 byte);
plsql_block VARCHAR2(4000 byte);
TYPE t_emp_tab IS TABLE OF emp.ename%TYPE;
l_ename_tab t_emp_tab;
BEGIN
case_when_logic := q'[WHEN ENAME = 'KING' THEN 'BOSS' ELSE 'NOBODY']';
plsql_block := q'[SELECT
CASE ]'||case_when_logic||q'[
END
FROM
emp WHERE ename = :name]';
EXECUTE IMMEDIATE plsql_block BULK COLLECT INTO l_ename_tab USING 'KING';
FOR r IN 1 .. l_ename_tab.COUNT LOOP
dbms_output.put_line(l_ename_tab(r));
END LOOP;
END;
/
如果你必须循环遍历一个数字 if WHEN x THEN y
子句然后连接你的语句。传递给 EXECUTE IMMEDIATE
时语句必须完整
DECLARE
plsql_block VARCHAR2(4000 byte);
TYPE vc_tab IS TABLE OF VARCHAR2(4000);
l_case_when_logic_tab vc_tab;
TYPE t_emp_tab IS TABLE OF emp.ename%TYPE;
l_ename_tab t_emp_tab;
BEGIN
l_case_when_logic_tab := vc_tab
(q'[WHEN JOB = 'PRESIDENT' THEN 'BOSS' ]',
q'[WHEN JOB = 'MANAGER' THEN 'TRYHARD' ]',
q'[WHEN JOB = 'SALESMAN' THEN 'STORYTELLER' ]'
);
plsql_block := q'[SELECT CASE ]';
FOR i IN l_case_when_logic_tab.FIRST .. l_case_when_logic_tab.LAST LOOP
plsql_block := plsql_block || l_case_when_logic_tab(i);
END LOOP;
plsql_block := plsql_block ||q'[
END
FROM
emp WHERE ename = :name]';
dbms_output.put_line('statement: ');
dbms_output.put_line(plsql_block);
EXECUTE IMMEDIATE plsql_block BULK COLLECT INTO l_ename_tab USING 'KING';
FOR r IN 1 .. l_ename_tab.COUNT LOOP
dbms_output.put_line(l_ename_tab(r));
END LOOP;
END;
/
我想知道是否可以在 Oracle SQL 中动态评估 select
语句中的 case 语句。以下面伪sql代码为例:
WITH temp AS (
SELECT
'WHEN ' || when_col || ' THEN ''' || then_value || '''' as case_logic
FROM some_table
)
SELECT
case
{temp.case_logic} -- EVALUATE THIS FOR ALL ROWS IN TEMP DURING RUNTIME
else 'NA'
end as case_when,
table2.*
FROM table2;
我尝试用占位符实现上述内容,如下所示:
DECLARE
case_when_logic VARCHAR2(4000 byte);
plsql_block VARCHAR2(4000 byte);
TYPE case_when_logic_tbl_type IS TABLE OF VARCHAR2(1000 BYTE);
case_when_logic_tbl case_when_logic_tbl_type;
BEGIN
case_when_logic := q'[SELECT 'WHEN ' | | when_condition_col | | ' THEN ''' | | then_condition_col | | '''' as case_when FROM some_table]';
execute immediate case_when_logic BULK COLLECT INTO case_when_logic_tbl;
plsql_block := q'[SELECT CASE :case_when
ELSE 'some other value'
END case_when_col,
table2.*
FROM table2]';
EXECUTE IMMEDIATE plsql_block USING case_when_logic_tbl;
END;
/
但不幸的是,这会引发错误:
PLS-00457: expressions have to be of SQL types
有没有办法做到这一点?请提供代码示例,因为我没有看到类似的解决方案。
execute immediate 中的 USING
子句采用位置表示法 (docs). So you can't pass a associative array. And you can only pass valid bind variables (explained here) 中的绑定变量。没有 table 名称、条款等
您可以连接 select 语句并执行如下操作:
DECLARE
case_when_logic VARCHAR2(4000 byte);
plsql_block VARCHAR2(4000 byte);
TYPE t_emp_tab IS TABLE OF emp.ename%TYPE;
l_ename_tab t_emp_tab;
BEGIN
case_when_logic := q'[WHEN ENAME = 'KING' THEN 'BOSS' ELSE 'NOBODY']';
plsql_block := q'[SELECT
CASE ]'||case_when_logic||q'[
END
FROM
emp WHERE ename = :name]';
EXECUTE IMMEDIATE plsql_block BULK COLLECT INTO l_ename_tab USING 'KING';
FOR r IN 1 .. l_ename_tab.COUNT LOOP
dbms_output.put_line(l_ename_tab(r));
END LOOP;
END;
/
如果你必须循环遍历一个数字 if WHEN x THEN y
子句然后连接你的语句。传递给 EXECUTE IMMEDIATE
DECLARE
plsql_block VARCHAR2(4000 byte);
TYPE vc_tab IS TABLE OF VARCHAR2(4000);
l_case_when_logic_tab vc_tab;
TYPE t_emp_tab IS TABLE OF emp.ename%TYPE;
l_ename_tab t_emp_tab;
BEGIN
l_case_when_logic_tab := vc_tab
(q'[WHEN JOB = 'PRESIDENT' THEN 'BOSS' ]',
q'[WHEN JOB = 'MANAGER' THEN 'TRYHARD' ]',
q'[WHEN JOB = 'SALESMAN' THEN 'STORYTELLER' ]'
);
plsql_block := q'[SELECT CASE ]';
FOR i IN l_case_when_logic_tab.FIRST .. l_case_when_logic_tab.LAST LOOP
plsql_block := plsql_block || l_case_when_logic_tab(i);
END LOOP;
plsql_block := plsql_block ||q'[
END
FROM
emp WHERE ename = :name]';
dbms_output.put_line('statement: ');
dbms_output.put_line(plsql_block);
EXECUTE IMMEDIATE plsql_block BULK COLLECT INTO l_ename_tab USING 'KING';
FOR r IN 1 .. l_ename_tab.COUNT LOOP
dbms_output.put_line(l_ename_tab(r));
END LOOP;
END;
/