There is one situation where using a computed field as a search key is required--when the field you want to search on is a REAL or DECIMAL data type. Neither of these two is valid for use as a search key. Therefore, making the search key a computed STRING field containing the value to search on is a way to get around this limitation.
The trick to computed fields in the payload is the same for search keys--build the content of the INDEX beforehand. The following example code (contained in IndexREALkey.ECL) illustrates how to accomplish this by building the content of computed search key fields on which the INDEX is built using a TABLE and PROJECT:
IMPORT $; r := RECORD REAL8 Float := 0.0; DECIMAL8_3 Dec := 0.0; $.DeclareData.person.file; END; t := TABLE($.DeclareData.person.file,r); r XF(r L) := TRANSFORM SELF.float := L.PersonID / 1000; SELF.dec := L.PersonID / 1000; SELF := L; END; p := PROJECT(t,XF(LEFT)); DSname := '~PROGGUIDE::EXAMPLEDATA::KEYS::dataset'; IDX1name := '~PROGGUIDE::EXAMPLEDATA::KEYS::realkeytestIDX1'; IDX2name := '~PROGGUIDE::EXAMPLEDATA::KEYS::realkeytestIDX2'; OutName1 := '~PROGGUIDE::EXAMPLEDATA::KEYS::realkeytestout1'; OutName2 := '~PROGGUIDE::EXAMPLEDATA::KEYS::realkeytestout2'; OutName3 := '~PROGGUIDE::EXAMPLEDATA::KEYS::realkeytestout3'; OutName4 := '~PROGGUIDE::EXAMPLEDATA::KEYS::realkeytestout4'; OutName5 := '~PROGGUIDE::EXAMPLEDATA::KEYS::realkeytestout5'; OutName6 := '~PROGGUIDE::EXAMPLEDATA::KEYS::realkeytestout6'; DSout := OUTPUT(p,,DSname,OVERWRITE); ds := DATASET(DSname,r,THOR); idx1 := INDEX(ds,{STRING13 FloatStr := REALFORMAT(float,13,3)},{ds},IDX1name); idx2 := INDEX(ds,{STRING13 DecStr := (STRING13)dec},{ds},IDX2name); Bld1Out := BUILD(idx1,OVERWRITE); Bld2Out := BUILD(idx2,OVERWRITE); j1 := JOIN(idx1,idx2,LEFT.FloatStr = RIGHT.DecStr); j2 := JOIN(idx1,idx2,KEYED(LEFT.FloatStr = RIGHT.DecStr)); j3 := JOIN(ds,idx1,KEYED((STRING10)LEFT.float = RIGHT.FloatStr)); j4 := JOIN(ds,idx2,KEYED((STRING10)LEFT.dec = RIGHT.DecStr)); j5 := JOIN(ds,idx1,KEYED((STRING10)LEFT.dec = RIGHT.FloatStr)); j6 := JOIN(ds,idx2,KEYED((STRING10)LEFT.float = RIGHT.DecStr)); JoinOut1 := OUTPUT(j1,,OutName1,OVERWRITE); JoinOut2 := OUTPUT(j2,,OutName2,OVERWRITE); JoinOut3 := OUTPUT(j3,,OutName3,OVERWRITE); JoinOut4 := OUTPUT(j4,,OutName4,OVERWRITE); JoinOut5 := OUTPUT(j5,,OutName5,OVERWRITE); JoinOut6 := OUTPUT(j6,,OutName6,OVERWRITE); SEQUENTIAL(DSout,Bld1Out,Bld2Out,JoinOut1,JoinOut2,JoinOut3,JoinOut4,JoinOut5,JoinOut6);
This code starts with some filename definitions. The record structure adds two fields to the existing set of fields from our base dataset: a REAL8 field named "float" and a DECIMAL12_6 field named "dec." These will contain our REAL and DECIMAL data that we want to search on. The PROJECT of the TABLE puts values into these two fields (in this case, just dividing the PersonID file by 1000 to achieve a floating point value to use that will be unique).
The IDX1 INDEX definition creates the REAL search key as a STRING13 computed field by using the REALFORMAT function to right-justify the floating point value into a 13-character STRING. This formats the value with exactly the number of decimal places specified in the REALFORMAT function.
The IDX2 INDEX definition creates the DECIMAL search key as a STRING13 computed field by casting the DECIMAL data to a STRING13. Using the typecast operator simply left-justifies the value in the string. It may also drop trailing zeros, so the number of decimal places is not guaranteed to always be the same.
Because of the two different methods of constructing the search key strings, the strings themselves are not equal, although the values used to create them are the same. This means that you cannot expect to "mix and match" between the two--you need to use each INDEX with the method used to create it. That's why the two JOIN operations that demonstrate their usage use the same method to create the string comparison value as was used to create the INDEX. This way, you are guaranteed to achieve matching values.