使用变量排除其他范围包含的一系列值

时间:2015-01-01 17:39:38

标签: sql oracle plsql

我有两个描述范围的变量; fromto。但是,我的代码中定义的范围之间存在一些重叠。我想通过使用变量从范围中排除一个值,因为我将这些变量作为参数传递给包来调用其他程序。

例如,如果我有这段代码:

 IF name = 'AA'
    THEN
       from := '101-0000-0000';
       to := '101-9999-9999';
    ELSIF name = 'BB'
    THEN
       from := '200-0000-0000';
       to := '200-9999-9999';
    ELSIF name = 'CC'
    THEN
       from := '100-0000-0000';
       to := '120-9999-0000';
    ELSIF name = 'DD'
    THEN
       from := '400-0000-0000';
       to := '402-9999-9999';
    END IF;

我想从101-****-****范围中排除name = 'CC'值,因为它们已被name = 'AA'范围使用。 CC from值为100-0000-0000,值为120-9999-9999,完全涵盖101-****-****

1 个答案:

答案 0 :(得分:1)

你不能以你想要的方式做到这一点。您将不得不拥有更多变量,例如from2to2(或将它们放在数组中)。如果你需要排除2个范围,那么你将需要3组变量等。因此,这种方法不可扩展,只会导致无法维护的代码膨胀。我认为你已经到了那里。

但是,你确实有一个数据库可供使用。用它来擅长它。创建一个表。

create table name_ranges ( 
     name varchar2(2) not null
   , min_value varchar2(13) not null
   , max_value varchar2(13) not null
   , constraint pk_name_ranges primary key (name, min_value)
   , constraint uk_name_ranges_min unique (min_value)
   , constraint uk_name_ranges_max unique (max_value)
   , constraint ck_name_ranges_min_max check (min_value <= max_value)
     );

insert into name_ranges values ('AA', '101-0000-0000', '101-9999-9999');
insert into name_ranges values ('BB', '200-0000-0000', '200-9999-9999');
insert into name_ranges values ('CC', '100-0000-0000', '100-9999-9999');
insert into name_ranges values ('CC', '102-0000-0000', '120-9999-9999');
insert into name_ranges values ('DD', '400-0000-0000', '402-9999-9999');

我把这些数字保留为VARCHARs;但我会考虑将它们改为NUMBER。当您需要显示数据时,可以添加分隔符,但它们只会使剩余的时间内管理数字变得更加困难。虽然我添加了一些约束,但是没有办法保证没有重叠的范围;在代码中声明这些时,你必须要小心。

现在,每当您需要根据这些范围从另一个表中选择数据时,您可以使用正常的非等连接加入:

select my.*
  from my_table my
  join name_ranges nr
    on my.name = nr.range
   and my.column_name between nr.min_value and nr.max_value

这有利于简化代码并减少音量。这也意味着如果您需要更改任何内容,则只需更改表格即可。没有其他的。从长远来看,它可以节省所以非常麻烦,令人难以置信。如果您对范围所做的某些选择的推理不清楚,请在使用自由文本填充的表格中添加一个描述列来解释它们。

如果您必须在代码中将这些作为变量,那么声明一个类型,该类型是实际表的表,然后将它们放入其中。

declare
   type t__name_ranges is table of name_ranges index by binary_integer;
   t_name_ranges t__name_ranges;
begin
   select * bulk collect into t_name_ranges
     from name_ranges;

   -- do_something
end;