*************************************************************************** * Description.......: GetMedianValue - returns median value from a specified table * Calling Samples...: GetMedianValue('TranMstr','Price','Price between 100000 and 130000') * Parameter List....: pcTableName, pcField, pcWhere * Created by........: Daniel Rouleau - original idea, Andrew Coates - Median definition * Modified by.......: Nadya Nosonovsky 10/30/2000 01:06:58 PM ***************************************************************************** * Returns median value or .f. for unsuccessful cases lparameters pcTableName, pcField, pcWhere * pcTableName - name of the table or already opened cursor, which should be processed * pcFiled - name of the field, which used in calculation, price, for example * pcWhere - where expression suitable for macro * All parameters are optional, if they are not specified, current working alias is used and price field ** Check parameters first if empty(pcTableName) or vartype(pcTableName)<>'C' pcTableName=alias() && Current open alias if empty(pcTableName) && No current table return .f. endif endif if empty(pcField) or vartype(pcField)<>'C' pcField=upper('price') else pcField=upper(pcField) endif if empty(pcWhere) or vartype(pcWhere)<>'C' pcWhere='' else pcWhere='where '+pcWhere endif local lnMiddleRecord, lcCursor, lnOldSelect, lnMedianValue lnOldSelect=select() && Save current area lcCursor='cur'+sys(2015) && Unique name if used(lcCursor) && this should never happen use in (lcCursor) endif select &pcField from (pcTableName) ; &pcWhere ; order by 1 ; into cursor (lcCursor) nofilter if _tally>3 lnMiddleRecord=(_tally/2) && Find middle record else =messagebox('Number of records is less than 3. Can not calculate median...',48) if used(lcCursor) use in (lcCursor) endif select (lnOldSelect) && Return to the original area return .f. endif do case case int(lnMiddleRecord)==lnMiddleRecord && Even number of records local lnLowMedValue, lnHighMedValue go lnMiddleRecord lnLowMedValue = evaluate(lcCursor + '.' + pcField) skip && Go to the next record in sequence lnHighMedValue = evaluate(lcCursor + '.' + pcField) lnMedianValue = round((lnLowMedValue+lnHighMedValue)/2,0) && Average of the two middle numbers otherwise && Odd number of records go int(lnMiddleRecord)+1 lnMedianValue=evaluate(lcCursor + '.' + pcField) endcase use in (lcCursor) && Close cursor select (lnOldSelect) && Return to the original area return lnMedianValue>This is another version of this program. It works much faster, if we have a necessary index.
*************************************************************************** * Description.......: GetMedian - returns median value from a specified table * Calling Samples...: GetMedian('curPrice','LstSlPrice') * Parameter List....: pcTableName, pcField * Created by........: Ideas - Andrew Coates * Modified by.......: Nadya Nosonovsky 10/30/2000 05:22:53 PM ***************************************************************************** * Returns median value or .f. for unsuccessful cases lparameters pcTableName, pcField local lcTableName, lnOldSelect, lnMedianValue, llCloseDBF, lnMiddleRecord, lcOrder * pcTableName - name of the table or already opened cursor, which should be processed * pcFiled - name of the field, which used in calculation, price, for example * Both parameters are optional, if they are not specified, current working alias is used and price field lnOldSelect=select() && Save current area llCloseDBF=.f. if empty(pcField) or vartype(pcField)<>'C' pcField=upper('price') else pcField=upper(pcField) endif if empty(pcTableName) or vartype(pcTableName)<>'C' pcTableName=alias() && Current open alias if empty(pcTableName) && No current table return .f. endif lcTableName=pcTableName && Alias else lcTableName=justfname(pcTableName) && Only Table Name without path if not used(lcTableName) && The table was not used previously local fh fh=fopen(pcTableName,12) if fh>0 and fclose(fh)>0 && File could be open exclusevely use pcTableName again shared in 0 alias lcTableName llCloseDBF=.t. else =messagebox(pcTableName +' is opened exclusively by another user. Can not proceed...',48) return .f. && Table could not be opened (already used exclusively) endif endif endif select (lcTableName) lnRecords=reccount() && Total number of records if lnRecords<3 =messagebox('Number of records is less than 3. Can not calculate median...',48) select (lnOldSelect) && Return to old area return .f. endif lcOrder=tag() && Save current order if tagno(pcField)=0 && Index on this field doesn't exist ** Now we have to open this table exclusively if isexclusive(lcTableName) && Table is opened exclusively already select (lcTableName) index on &pcField tag (pcField) else fh=fopen(pcTableName,12) if fh>0 and fclose(fh)>0 && File could be open exclusevely use dbf(lcTableName) again exclusive in 0 alias WorkTable select WorkTable index on &pcField tag (pcField) use in WorkTable else =messagebox(pcTableName +' is opened exclusively by another user. Can not proceed...',48) return .f. && Table could not be opened (already used exclusively) endif endif else endif select (lcTableName) set order to (pcField) && Now it has this tag go top lnMiddleRecord=lnRecords/2 do case case int(lnMiddleRecord)==lnMiddleRecord && Even number of records local lnLowMedValue, lnHighMedValue skip lnMiddleRecord-1 lnLowMedValue = evaluate(lcTableName + '.' + pcField) skip && Go to the next record in sequence lnHighMedValue = evaluate(lcTableName + '.' + pcField) lnMedianValue = round((lnLowMedValue+lnHighMedValue)/2,0) && Average of the two middle numbers otherwise && Odd number of records skip int(lnMiddleRecord) lnMedianValue=evaluate(lcCursor + '.' + pcField) endcase if llCloseDBF use in (lcTableName) else set order to (lcOrder) endif select (lnOldSelect) && Return to old area return lnMedianValue>>Nadja,