这是一个复杂的解释,很抱歉,这将是一堵文字墙。我正在处理预先存在的代码并试图找出解决方案,所以我无法改变其中任何一个工作的核心方式。
本质上,我在一个项目中有一系列表单,所有这些表单都有一个分配给它们的状态。状态具有指定的优先顺序,这将逐渐向上级访问。当前的工作方式使用以下 sql 语句:
select state_code
from (select ' || v_priorstr || '
from m_object mo, m_form mf
where mo.id = mf.id
and mf.formlayout_id = :1
and mo.v = :2)
unpivot
(
state_counts
for state_code in (' || v_priorstr || ')
) where state_counts = 1 and rownum = 1
Run Code Online (Sandbox Code Playgroud)
其中 v_priorstr 是逗号分隔的状态字符串,按优先顺序排列。例如,考虑以下字符串:“Blank,Error,InProgress,Completed”。m_object 表包含这些列中的每一列,用 0 或 1 显示适用的状态。(表单可以有多个状态)此查询选择最高优先级的状态,然后将用于显示该表单的状态图标。
处理重复表单时会出现问题(在一个链接下可以有多次迭代)。它们都在导航系统中共享一个状态图标。
虽然通常这很好用,因为 SQL 会自然地按照您请求的顺序显示列,并且它们在未旋转时保持该顺序。但是,对于多个表单,因此也有多个行,第一个表单/行的所有状态都绝对优先于所有表单的状态。
例如,如果我有两个这样的重复形式,第一个是“已完成”,第二个是“错误”,上面的查询(没有 rownum = 1)将返回以下两行:
Completed
Error
Run Code Online (Sandbox Code Playgroud)
到目前为止,我尝试了以下解决方案:
没有 Order By 的 Group By 将取消订单。我不能使用基于案例的 Order By,因为状态名称可能会改变。
简而言之,我需要它按照通过该字符串传入的顺序对状态名称进行排序或分组。
这使用与 jonearles (+1)(已删除)相同的基本技术,但消除了PIVOT
and ,只需要一个将字符串转换为CASE
语句的函数。
SELECT substr(
MIN (
CASE WHEN Blank=1 THEN '1 Blank'
WHEN Error=1 THEN '2 Error'
WHEN InProgress=1 THEN '3 InProgress'
WHEN Completed=1 THEN '4 Completed'
END
)
,3) state_code
FROM m_object mo
JOIN m_form mf ON mo.id = mf.id
WHERE mo.v = :2 AND mf.formlayout_id = :1;
Run Code Online (Sandbox Code Playgroud)
我假设数据看起来像这样:
drop table m_object;
create table m_object as
(select 10 id, 0 blank, 0 error, 0 inprogress, 1 completed, 99 v from dual);
insert into m_object values (11,1,0,0,0,99);
insert into m_object values (12,0,0,0,1,99);
insert into m_object values (13,0,1,1,0,99);
drop table m_form;
create table m_form as (select 10 id, 20 formlayout_id from dual);
insert into m_form values (11,21);
insert into m_form values (12,22);
insert into m_form values (13,20);
Run Code Online (Sandbox Code Playgroud)
如果该函数是在 PL/SQL 中完成的,则该函数可能如下所示。它只是拼凑在一起,仅用于说明如何构建 SQL 语句,而不是良好编码的示例。
set serveroutput on format wrapped
DECLARE
vPassed Varchar2(500) := 'Blank,Error,InProgress,Completed';
Function MakeCase(pOriginal In Varchar2) Return Varchar2 Is
vBuilt Varchar2(500);
vWord Varchar2(100);
vChar Char(1);
vWordCount Number(1) := 1;
Begin
For vLoop In 1..Length(pOriginal) Loop
vChar := substr(pOriginal,vLoop,1);
If (vChar = ',') Then
If (vBuilt IS NULL) Then
vBuilt := 'CASE WHEN ';
End If;
vBuilt := vBuilt || vWord || '=1 THEN '''
|| to_char(vWordCount,'FM0') || ' ' || vWord || ''' WHEN ';
vWord := '';
vWordCount := vWordCount + 1;
Else
vWord := vWord || vChar;
End If;
End Loop;
vBuilt := vBuilt || vWord || '=1 THEN '''
|| to_char(vWordCount,'FM0') || ' ' || vWord || ''' ';
vBuilt := vBuilt || ' END ';
Return vBuilt;
End;
BEGIN
vPassed := MakeCase(vPassed);
DBMS_Output.Put_Line(vPassed);
--Use vPassed here to build SQL statement.
END;
/
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1157 次 |
最近记录: |