Create Cursor myreportcursor (invid I,invno C(10),batchno I)Now you prepare employee columns
For nLoop=1 To 9 cFieldname1='empcharge'+Transform(nLoop) cFieldname2='empbook'+Transform(nLoop) Alter Table myreportcursor Add Column &cFieldname1. N(4,1) Add Column &cFieldname2. N(4,1) EndforNow you collect employees
Select Distinct EmpID,EmpName From InvoiceDataTable Join EmployeeTable On ... Where .... Order By 2 Into Cursor reportemployeesNow you can start collecting data for each employee filling it to the report cursor:
Select myreportcursor Index On Str(batchno)+str(InvId) Tag BatchInvoice Set Order To Tag EmpId in InvoiceEmpData && this is either full data or recordset collected by some invoice criteria Select reportemployees nCounter=0 Scan nCounter=nCounter+1 nFieldnumber=mod(nCounter,9) && use it to fill proper field in the reportcursor if nFieldnumber=0 nFieldnumber=9 endif nBatchno=ceiling(nCounter/9) && first 9 employees go to 1st batch, next 9 to 2nd batch and so on nEmpId=reportemployees.empid && use this id to collect hours from invoice/hours tables Select InvoiceEmpData Seek nEmpId Scan While InvoiceEmpData.EmpId=nEmpId nInvID=InvoiceEmpData.InvID *** check in hours tables to collect hours per InvId+EmpId, getting nCharge (charged hours) and nBooked (booked hours) If seek(Str(nBatchno)+Str(nInvID),'myreportcursor','BatchInvoice')=.F. && add new record Insert into myreportcursor (invid,invno,batchno) values(nInvID,cInvno,nBatchno) endif cFieldname1='empcharge'+transform(nFieldnumber) cFieldname2='empbook'+transform(nFieldnumber) Replace &cFieldname1. With nCharge,&cFieldname2. With nBooked in myreportcursor EndScan EndScanPlease, note that I didn't test the code, so check for typos, and use actual table/field names. There are few auxiliary things that may transpire on the way, so do it methodically. Good luck.