Oracle 使用函数计算字符串的替代方法

Oracle 使用函数计算字符串的替代方法,oracle,oracle12c,Oracle,Oracle12c,我试图输出一个记录列表,但有些记录在主题列中可能没有值。 我有一个altSubject列,它将指定要输出的内容 例如简化的 insert all into myTable (id, subject, altSubject, partNumber, serialNumber, startDate, endDate) values (1, 'test',null,'xyz','123','1/1/2019', '1/5/2019')

我试图输出一个记录列表,但有些记录在主题列中可能没有值。 我有一个altSubject列,它将指定要输出的内容

例如简化的

insert all 
    into myTable 
        (id, subject, altSubject, partNumber, serialNumber, startDate, endDate) 
        values
        (1, 'test',null,'xyz','123','1/1/2019', '1/5/2019') 
    into myTable 
        (id, subject, altSubject, partNumber, serialNumber, startDate, endDate) 
        values
        (2, null, '''SN: '' || serialNumber','abc','789','1/1/2019', '1/5/2019') 
输出应如下所示:

subject | Part Number | Start Date | End Date
test    | xyz         | 1/1/2019   | 1/5/2019
SN: 789 | abc         | 1/1/2019   | 1/5/2019
我已经能够使用下面带有函数的case来实现这一点,但我遇到的问题是在40k行表上运行需要5分钟

select
    ...
    ...
    case when altSubject is not null then
        fAltSubject(id,altSubject)
    else
      subject
    end subject
from
    myTable
where
    status = 'closed'
职能:

create or replace function fAltSubject
    (pID in number
    , pAltSubject in varchar2)
    return varchar2 
  as
    vNewSubject varchar2(400) := '';
  begin
    vSql := 'select ' ||
      pAltSubject ||
      ' from
          myTable
        where
          id = ' || pID;
    execute immediate vSql
     into 
       vNewSubject;
    return vNewSubject;
end faltsubject;
有没有一种不需要5分钟的更好方法


提前感谢。

您拥有Oracle的最新版本:祝贺您。所以使用它:虚拟列

create table myTable (
  id number, 
  subject varchar2(32), 
  altSubject varchar2(64)
    generated always as (case when subject is null then 'SN: '||serialnumber end), 
  partNumber varchar2(16), 
  serialNumber varchar2(16), 
  startDate date, 
  endDate date
);

insert into mytable(id, subject, partnumber, serialnumber, startdate, enddate)
select 1, 'test','xyz','123',sysdate, sysdate+1 from dual
union all 
select 2, null,'abc','789',sysdate, sysdate+1 from dual;

select ID, coalesce(SUBJECT, ALTSUBJECT) subject,
  PARTNUMBER, SERIALNUMBER, STARTDATE, ENDDATE
from mytable;

ID SUBJECT  PARTNUMBER  SERIALNUMBER  STARTDATE           ENDDATE            
-- -------- ----------- ------------- ------------------- -------------------
 1 test     xyz         123           2019-12-18 13:09:10 2019-12-19 13:09:10
 2 SN: 789  abc         789           2019-12-18 13:09:10 2019-12-19 13:09:10
这可能太过分了。你总是可以摆脱多余的专栏,说:

select ID, coalesce(SUBJECT, 'SN: '||serialnumber) subject,
  PARTNUMBER, SERIALNUMBER, STARTDATE, ENDDATE
from mytable;
致以最良好的祝愿, Stew Ashton

“当掩码可以是字段和文本的组合时,如何在列中使用用户定义的掩码”

这是我所能做的最好的了,我的表现也很好

该表定义了主题、AltSubject和DisplaySubject

触发器根据其他两个字段设置DisplaySubject

触发器必须引用特定的列名,因此每次添加列时都需要重新生成触发器。也许是夜间工作

create table myTable (
  id number, 
  subject varchar2(64), 
  altSubject varchar2(128),
  displaySubject varchar2(128),
  partNumber varchar2(16), 
  serialNumber varchar2(16), 
  startDate date, 
  endDate date
);

create or replace procedure generate_mytable_trigger is
l_newline constant varchar2(1) := chr(10);
l_text clob := to_clob(
'create or replace trigger mytable_displaysubject
before insert or update on mytable
for each row
declare
  lt_column_names sys.odcivarchar2list;
begin
  if :new.subject is not null then
    :new.altsubject := null;
    :new.displaysubject := :new.subject;
    return;
  end if;
  :new.displaysubject := :new.altsubject;
  -- start lines to be generated');
l_end_text constant varchar2(4000) := 
'-- end lines to be generated
  return;
end mytable_displaysubject;';
begin
  for rec in (
    select l_newline ||
      ':new.displaysubject := replace(:new.displaysubject, ''#'||column_name||'#'', :new.'||column_name||');'
      as text
    from user_tab_columns where table_name = 'MYTABLE'
    and column_name not in ('SUBJECT','ALTSUBJECT','DISPLAYSUBJECT')
  ) loop
    l_text := l_text || rec.text;
  end loop;
  l_text := l_text || l_newline || l_end_text;
  execute immediate l_text;
end;
/

exec generate_mytable_trigger;
现在进行一个小测试:

insert into mytable(id, subject, altsubject, partnumber, serialnumber, startdate, enddate)
select 1, 'test',null,'xyz','123',sysdate, sysdate+1 from dual
union all 
select 2, null,'PN: #PARTNUMBER#','abc','789',sysdate, sysdate+1 from dual
union all 
select 3, null,'PN: #PARTNUMBER#, SN: #SERIALNUMBER#','qsdf','789',sysdate, sysdate+1 from dual
union all 
select 3, null,'PN: #PARTNUMBER#, ??: #BADCOLUMN#','qsdf','789',sysdate, sysdate+1 from dual;
commit;

select subject, altsubject, displaysubject from mytable;

SUBJECT   ALTSUBJECT                             DISPLAYSUBJECT              
test                                               test                         
           PN: #PARTNUMBER#                        PN: abc                      
           PN: #PARTNUMBER#, SN: #SERIALNUMBER#    PN: qsdf, SN: 789            
           PN: #PARTNUMBER#, ??: #BADCOLUMN#       PN: qsdf, ??: #BADCOLUMN#

使用绑定参数(请参阅)可以加快函数的运行速度。另见@SternK谢谢。我尝试使用pAltSubject,pID
executeimmediate'select:newSubject from myTable where id=:id'进入vNewSubject,但结果是
'SN:'| | serialNumber
而不是
SN:789
我缺少什么吗?请参阅。绑定变量是一个值或值地址,而不是一个表或列名,您建议我如何使用绑定变量?类似于这样的
使用pID
从myTable执行立即“select”| | | pAltSubject | | | | id”到vNewSubject。我的问题是,根据我正在查看的文档类型,altSubject是不同的,因此我尝试将其作为可选设置从表中拉出来文件。它可能是
'SN:'| | serialnumber
someColumn | |]['| | |另一列| |']
或任何客户希望看到的alt主题。我想是这样的。不要那样做。这是代码,不是数据。要求客户定义文档类型以及他们希望看到的每种类型的替代主题。然后在CASE表达式中对这些备选方案进行编码。好的,如果每个文档的备选主题不同,那么为什么不直接输入'SN:789'作为主题???应用程序允许我添加一个文档,有时有主题,有时没有。有时我不得不添加一列来满足文档需求,但这一切都是自动完成的。如果文档没有主题,系统需要能够用其他内容替换它,而无需在每次创建新文档类型时更改代码。(它实际上不是一个“文档”,它比这个复杂一点,即一个动态售票系统)我愿意接受建议,但每周修改代码不是一个选项。“如果替代主题随每个文档而变化,那么为什么不输入'SN:789'作为主题呢?”正如我所说的,这是一个简单的例子。票证类型可能没有“主题”,但主要主题可能是从下拉列表或字段组合中选择的
手册编号
服务说明
。大多数票证使用
主题
字段,但有些不使用,我需要一种方法来处理它,而无需在每次客户添加带有自定义字段的新票证类型时修改应用程序。“主要主题可能是从下拉列表中选择的手动编号或维修说明,或多个字段的组合。”然后用户通过下拉选择“输入”一个值!因此,只需计算该选择的结果并将其放入字段,而不是每次都在字段中放入一些代码来计算结果。顺便问一下,在不更改应用程序的情况下,如何将新的自定义字段添加到下拉列表中?这是有潜力的。我喜欢你所做的coldfusion#variable#parse功能。我不是“展示”专栏的超级粉丝,我们把这个想法抛诸脑后,决定把它列为旅游胜地。目前,我已经使用临时表在几秒钟内运行了它,但是在构建临时表的过程中,随着带掩码的行的增长,可能会出现性能问题。psudo:
插入temp select id,subject,其中altSubject为null
,然后我在循环中一次添加一个屏蔽行。联接临时表以获取查询中的主题。10公里记录时15秒。慢,但不是5分钟。