Question

I've got a table in an Oracle 11gR2 database that contains five sequential fields, like Field1, Field2, Field3, Field4, and Field5.

These fields are related:

  • If Field2 is populated, Field1 has to be populated.
  • If Field5 is populated, all Fieldn fields should be populated.

What is the best way to validate that these fields are populated correctly?

For instance, the query should return cases where Field3 is populated, but Field1 and Field2 are not. Or when just Field4 is populated. Or when Field1 and Field3 are populated. Etc. I'd like to avoid 25 different conditions in my filter if possible.

Any help would be appreciated.

Was it helpful?

Solution

Probably the simplest way is a brute force approach:

select t.*
from t
where (t.field1 is null and coalesce(t.field2, t.field3, t.field4, t.field5) is not null) or
      (t.field2 is null and coalesce(t.field3, t.field4, t.field5) is not null) or
      (t.field3 is null and coalesce(t.field4, t.field5) is not null) or
      (t.field4 is null and t.field5 is not null);

OTHER TIPS

If the only valid scenario is to fill the fields in order, with no gaps, which I think is what you're saying, then you could work out the 'highest' field that is populated and the number of fields that are populated, and compare them. If there us a gap then those two numbers will be different. e.g.:

select field1, field2, field3, field4, field5 from (
  select field1, field2, field3, field4, field5,
    case when field1 is not null then 1 else 0 end
      + case when field2 is not null then 1 else 0 end
      + case when field3 is not null then 1 else 0 end
      + case when field4 is not null then 1 else 0 end
      + case when field5 is not null then 1 else 0 end as cnt,
    greatest(case when field1 is not null then 1 else 0 end,
      case when field2 is not null then 2 else 0 end,
      case when field3 is not null then 3 else 0 end,
      case when field4 is not null then 4 else 0 end,
      case when field5 is not null then 5 else 0 end) as grt
  from my_table
)
where cnt != grt;

SQL Fiddle demo.

As Michael-O points out, you could use nvl2 instead of case (shown in another SQL Fiddle), which is non-standard but arguably clearer:

select field1, field2, field3, field4, field5 from (
  select field1, field2, field3, field4, field5,
    nvl2(field1, 1, 0) + nvl2(field2, 1, 0) + nvl2(field3, 1, 0)
      + nvl2(field4, 1, 0) + nvl2(field5, 1, 0) as cnt,
    greatest(nvl2(field1, 1, 0), nvl2(field2, 2, 0), nvl2(field3, 3, 0),
      nvl2(field4, 4, 0), nvl2(field5, 5, 0)) as grt
  from t42
)
where cnt != grt;

If you wanted to enforce this you could add a check constraint to do the same comparison:

alter table my_table add constraint my_check check (
  case when field1 is not null then 1 else 0 end
    + case when field2 is not null then 1 else 0 end
    + case when field3 is not null then 1 else 0 end
    + case when field4 is not null then 1 else 0 end
    + case when field5 is not null then 1 else 0 end
  = greatest(case when field1 is not null then 1 else 0 end,
      case when field2 is not null then 2 else 0 end,
      case when field3 is not null then 3 else 0 end,
      case when field4 is not null then 4 else 0 end,
      case when field5 is not null then 5 else 0 end));

Since you're using 11gR2 you could do this with virtual columns as well:

alter table my_table add cnt generated always as
  (case when field1 is not null then 1 else 0 end
    + case when field2 is not null then 1 else 0 end
    + case when field3 is not null then 1 else 0 end
    + case when field4 is not null then 1 else 0 end
    + case when field5 is not null then 1 else 0 end);

alter table my_table add grt generated always as
  (greatest(case when field1 is not null then 1 else 0 end,
    case when field2 is not null then 2 else 0 end,
    case when field3 is not null then 3 else 0 end,
    case when field4 is not null then 4 else 0 end,
    case when field5 is not null then 5 else 0 end));

alter table my_table add constraint my_check check (cnt = grt);

... but apart from the check itself maybe being clearer I don't think it adds much.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top