1984
(Starting to like KiXtart)
2007-09-25 08:33 PM
Need a script that read/collect and creates...

Hi,

I have an Excel file which contains hundreds of user IDs, contact information, location, department, and manager IDs for each of listed users.

I need a script which reads the current Excel file, find/collect all users belonging to each of the managers, and then for each “manager” it creates new Excel files/sheets containing all users that belong to that manager.

Excel sheet:

 Code:
A	B	C	D
ID:	Unit:	Site:	Manager:
userP	UnitBX	London	ManD
userX	UnitA	Paris	ManA
user54	Unit34	London	ManF
user23	Unit34	London	ManF
user01	UnitRR	Paris	ManC
user11	UnitBX	Madrid	ManA
user7	UnitZ	Madrid	ManD
user62	UnitRR	London	ManD
userTX	UnitA	Paris	ManD
userLA	UnitFM	Madrid	ManA
user05	UnitRV	London	ManC
user12	UnitZ	Paris	ManC




Could someone give me a hand on this please?

BR/CY


Glenn BarnasAdministrator
(KiX Supporter)
2007-09-25 08:40 PM
Re: Need a script that read/collect and creates...

look at this post for a library of Excel functions. Once you load such a library, you can call the functions like any other Kix command.

This library contains UDFs to read/write, Open, Save, create, and Format Excel worksheets.

Glenn


1984
(Starting to like KiXtart)
2007-09-25 11:31 PM
Re: Need a script that read/collect and creates...

Thanx Glenn,

I checked your UFDs, but cannot figure out which one, or how to use them to get the result I want, as I described earlier.

Let’s say I have same scenario as above but the list is a text file (*.txt) and a delimiter is used to separate each values, such as “;”.

 Code:
userP;UnitBX;London;ManD
userX;UnitA;Paris;ManA
user54;Unit34;London;ManF
user23;Unit34;London;ManF
user01;UnitRR;Paris;ManC
user11;UnitBX;Madrid;ManA
user7;UnitZ;Madrid;ManD
user62;UnitRR;London;ManD
userTX;UnitA;Paris;ManD
userLA;UnitFM;Madrid;ManA
user05;UnitRV;London;ManC
user12;UnitZ;Paris;ManC


Now how can I read that text file, find/collect all users belonging to each of the managers, and then for each “manager” generate new text file containing all users that belong to that manager.


Witto
(MM club member)
2007-09-26 12:42 AM
Re: Need a script that read/collect and creates...

You can always use your macro recorder to catch some code and use it in a script
Here is maybe an idea for your first scenario
 Originally Posted By: 1984
have an Excel file which contains hundreds of user IDs, contact information, location, department, and manager IDs for each of listed users.

;*************************************************************************
;  Script Name:  
;  Author:        Wim Rotty
;  Date:          26/09/2007
;  Description:   Copy and paste data from one Excel book to other books
;*************************************************************************

 
;Script Options
If Not @LOGONMODE
    Break On
Else
    Break Off
EndIf
Dim $RC
$RC = SetOption("Explicit", "On")
$RC = SetOption("NoMacrosInStrings", "On")
$RC = SetOption("NoVarsInStrings", "On")
If @SCRIPTEXE = "KIX32.EXE"
    $RC = SetOption("WrapAtEOL", "On")
EndIf

;Declare variables
Dim
 
$MyTable
Dim $objExcel
Dim $xlDown, $xlToLeft, $xlToRight, $xlUp

;Initialize variables
$MyTable = "C:\Test\Tabel.xls"
$objExcel = CreateObject("Excel.Application")
If @ERROR
    Exit @ERROR
EndIf
$xlDown = -4121
$xlToLeft = -4159
$xlToRight = -4161
$xlUp = -4162

;Code
$objExcel.Visible = -1
$RC = $objExcel.Workbooks.Open($MyTable)
$RC = $objExcel.Selection.Autofilter
$RC = $objExcel.Range("A1").End($xlDown).End($xlToRight).Select
$RC = $objExcel.Range($objExcel.Selection, $objExcel.Cells(1)).Select
$RC = $objExcel.Selection.AutoFilter(4, "ManA")
$RC = $objExcel.Selection.Copy
$RC = $objExcel.Workbooks.Add
$RC = $objExcel.ActiveSheet.Paste
$RC = $objExcel.ActiveWindow.ActivateNext
$RC = $objExcel.Selection.AutoFilter(4, "ManC")
$RC = $objExcel.Selection.Copy
$RC = $objExcel.Workbooks.Add
$RC = $objExcel.ActiveSheet.Paste
$RC = $objExcel.ActiveWindow.ActivateNext
$RC = $objExcel.Selection.AutoFilter(4, "ManD")
$RC = $objExcel.Selection.Copy
$RC = $objExcel.Workbooks.Add
$RC = $objExcel.ActiveSheet.Paste
$RC = $objExcel.ActiveWindow.ActivateNext
$RC = $objExcel.Selection.AutoFilter(4, "ManF")
$RC = $objExcel.Selection.Copy
$RC = $objExcel.Workbooks.Add
$RC = $objExcel.ActiveSheet.Paste
$RC = $objExcel.ActiveWindow.ActivateNext
$RC = $objExcel.Selection.AutoFilter(4)

;Personal UDF Section

;UDF Section

Microsoft Excel Constants (Excel 2003 VBA Language Reference)


1984
(Starting to like KiXtart)
2007-09-26 01:02 AM
Re: Need a script that read/collect and creates...

Witto thanx for your wonderful code,

I see in your code that “managers” (ManD, ManA …) are manually defined .

But the problem is that there are more than 50 managers. I want to avoid manually defining each one in the code.

The script should also be automated to read and list managers without manually defining them in the code.


NTDOCAdministrator
(KiX Master)
2007-09-26 05:55 AM
Re: Need a script that read/collect and creates...

Well KiXtart is not exactly a match for doing this sort of manipulation of Excel data. I would recommend using the built-in VBA or if you're not familiar with it then this site here is like KiXtart.org only for EXCEL

There are a lot of very smart guys over there that can easily help you whip up something.

http://www.mrexcel.com/


Gargoyle
(MM club member)
2007-09-26 08:46 AM
Re: Need a script that read/collect and creates...

If your files are CSV files, then Kix can do what you want and output them to a CSV file as well.

Using your example...

 Code:
;Script Options
$SO=SETOPTION("Explicit", "ON")
$SO=SETOPTION("NoMacrosInStrings", "ON")
$SO=SETOPTION("NoVarsInStrings", "ON")
$SO=SETOPTION("WrapAtEOL", "ON")

If Not @LogonMode
	BREAK ON
EndIf

Dim $FH, $Line, $Managers[], $Count, $Manager, $Count2

$FH = FreeFileHandle()
$Count = 0


Open($FH,"C:\Support\MyInputFile.CSV")

$Line = Readline($FH)

While @Error = 0
	$Line = Split($Line,",")
	
	If InArray($Managers,$Line[3]) < 0
		Redim Preserve $Managers[$Count]
		$Managers[$Count] = $Line[3]
		$Count = $Count + 1
	EndIf
	$Line = Readline(1)
Loop

Close($FH)

Dim $Users[Ubound($Managers),0]

$Count = 0

For Each $Manager in $Managers
	$Count2 = 1
	$FH = FreeFileHandle()
	Open($FH,"C:\Support\MyInputFile.CSV")
	$Users[$Count,0] = $Manager
	$Line = Readline($FH)
	While @Error = 0
		$Line = Split($Line,",")
		If $Line[3] = $Manager
			$Users[$Count,$Count2] = $Line[0]
			$Count2 = $Count2 + 1
		EndIf
		$Line = Readline($FH)
	Loop
	$Count = $Count + 1
Next
Close($FH)

For $Count = 0 to Ubound($Users,1)
	$FH = FreeFileHandle()
	Open($FH,"C:\Output\"+$Users[$Count,0]+".csv",5)
	For $Count2 = 1 to Ubound($Users,2)
		Writeline($FH,$Users[$Count,$Count2]+@CRLF)
	Next
	Close($FH
Next


This does require the use of the UDF InArray so make sure you include it.

This Code sample is 100% UNTESTED.

This is just an example of one way to accomplish your task.


Richard H.Administrator
(KiX Supporter)
2007-09-26 09:56 AM
Re: Need a script that read/collect and creates...

No need for arrays, just redirect the output to a file as you read it.

I've kept it very simple and used RedirectOutput() to save strokes.

Input and ouput is assumed to be CSV (comma "," seperated values)

 Code:
Break ON
 
$=SetOption("Explicit","ON")
Dim $fh,$sFile,$sLine
 
$fh=FreeFileHandle()
$sFile=".\data.csv"
 
If Not Open($fh,$sFile)
	$sLine=ReadLine($fh)
	While Not @ERROR
		$sLine=SPlit($sLine,",")
		If UBound($sLine)=3
			$=RedirectOutput($sLine[3]+".csv")
			Join($sLine,",")+@CRLF
			$=RedirectOutput("")
		EndIf
		$sLine=ReadLine($fh)
	Loop
Else
	"Cannot open "+$sFile+" for reading"+@CRLF
EndIf


This code is 100% tested. \:\/


BradV
(Seasoned Scripter)
2007-09-26 01:31 PM
Re: Need a script that read/collect and creates...

I'd have to agree with NTDOC. You have an excel spreadsheet that contains the data you want to use to create more excel spreadsheets. I would use the onboard VBA.

Regards,

Brad V


Glenn BarnasAdministrator
(KiX Supporter)
2007-09-26 05:38 PM
Re: Need a script that read/collect and creates...

Some ideas based on the original request - read a file (excel or other) and group the data by manager. First a simple example reading data from Excel and gathering it in a temporary file. This could also be done if the source is a CSV-type file.

The second example shows how to take that temporary data and create CSV files for each manager. You could use the xlLib to create new XLS files as well.

Glenn

 Code:
;Working with Excel, for example

; Define an Excel object pointer
$oXL = xlInstantiateApp()
 
; Open the file
xlFile($oXL, 0, 'MyFile.xls')
 
; Return an array of 4 values from the first data row
; Start with row 2, since row 1 has titles
; keep reading until a blank row is returned
$Row = 2
 
While $Row > 0
  $Range = 'A' + CStr($Row) + ':D' + CStr($Row)
  $aData = xlRangeValue($oXL, $Range, , 'Sheet1')
 
  ; The first element of the array contains the user, fourth has the manager
  ; Howard Bullok has a great Hash UDF that would work well here, but 
  ; I'm going to use a "poor-man's" hash - an INI file, and reduce the number
  ; of UDFs required
 
  If $aData[0] = ''
    ; Anti-Golf to make it clear what data goes where
    $User = $aData[0]
    $Manager = $aData[3]
    $Record = Join($aData, Chr(31))	; Chr(31) is ASCII US - Unit Separator
    $ = WriteProfileString('.\hash.ini', $Manager, $User, $Record)
  Else
    $Row = -1     ; no more data - exit the loop
  EndIf
 
  $Row = $Row + 1
Loop




You now have a file that looks like this, with the data from the spreadsheet:
 Code:
[MANA]
UserX=userX;UnitA;Paris;ManA
User11=user11;UnitBX;Madrid;ManA
userLA=userLA;UnitFM;Madrid;ManA
[MANC]
User01=user01;UnitRR;Paris;ManC
User05=user05;UnitRV;London;ManC
User12=user12;UnitZ;Paris;ManC


and so on...

This groups users by manager, with the extracted data. You can then use the EnumINI() UDF to first get an array of manager IDs, and then a list of users by manager.

Of course, you could read a text file, use Split(string, ';') to convert to an array and write to the hash file in pretty much the same way.
In the example below, use the CSV() UDF to output properly formatted CSV records.


 Code:
; Get list of Managers
$aManagers = EnumIni('.\hash.ini')
For Each $Manager in $aManagers
  ; get the list of users for the current manager ID
  $aUsers = EnumIni('.\hash.ini', $Manager)

  ; the print statements are only for debugging/monitoring
  ; Removing them can streamline the process by placing the RedirectOutput commands
  ; outside of the Users For/Next loop
  'Manager is ' $Manager ?
  For Each $User in $aUsers
    $User ?
    $aData = Split(ReadProfileString('.\hash.ini', $Manager, $User), Chr(31))
    ; the original data is now in $aData array
    ; simple result - write a CSV record to a MANAGER.CSV file
    $ = RedirectOutput('.\' + $Manager + '.csv')
    CSV($aData) ?
    $ = RedirectOutput('')

  Next ; User

Next ; Manager


1984
(Starting to like KiXtart)
2007-09-26 08:17 PM
Re: Need a script that read/collect and creates...

Thanx a lot all for your input,

I have now tested using both CSV and text format.

Unfortunately I cannot make any of your later provided codes to work properly.

Richard:
Nothing happens!

Gargoyle:
Dim $Users[UBound($Managers),0] give the error: array reference out of bounds!.

Glenn:
xlFile gives error: unknown command!

Any suggestion?


Glenn BarnasAdministrator
(KiX Supporter)
2007-09-26 08:37 PM
Re: Need a script that read/collect and creates...

 Originally Posted By: 1984

Glenn:
xlFile gives error: unknown command!

Any suggestion?

Are you downloading the UDFs and including them in your script? (Either by directly copying / pasting, or via CALL statements?)
Do you have Excel installed on the machine where you are running this? You need Excel installed in order to instantiate a connection to it.

As far as my code examples, the logic should function. You'll need to add error checking, change file names and output formats and such, of course.

It's rare that I'll provide "silver-platter" code. 16 years as an IT instructor prevents that, but you will get a good hard shove in the right direction. ;\)

Glenn


1984
(Starting to like KiXtart)
2007-09-26 09:24 PM
Re: Need a script that read/collect and creates...

Yeap, Excel is in place (2007!) and code copied and pasted to ase.
Not meaning to be served "silver-platter" codes, but would like feedbacks that I could understand and learn :-)

Not a coder, just like kix :-)


1984
(Starting to like KiXtart)
2007-09-26 11:30 PM
Re: Need a script that read/collect and creates...

Oh sorry Glenn, I had a typo in the function part when pasting code.

However now I get this error :

"invalid method/function call: missing required parameter 3!"
referring to the line $_Sheet = IIf($_Sheet = '', $_ID.ActiveSheet.Name, $_Sheet)
in function section xlRangeValue

 Code:
; Define an Excel object pointer
$oXL = xlInstantiateApp()
 
; Open the file
xlFile($oXL, 0, 'C:\Bin\Book1.xls')
 
; Return an array of 4 values from the first data row
; Start with row 2, since row 1 has titles
; keep reading until a blank row is returned
$Row = 2
 
While $Row > 0
  $Range = 'A' + CStr($Row) + 'D' + CStr($Row)
  $aData = xlRangeValue($oXL, $Range, , 'Sheet1')
 
  ; The first element of the array contains the user, fourth has the manager
  ; Howard Bullok has a great Hash UDF that would work well here, but 
  ; I'm going to use a "poor-man's" hash - an INI file, and reduce the number
  ; of UDFs required
 
  If $aData[0] = ''
    ; Anti-Golf to make it clear what data goes where
    $User = $aData[0]
    $Manager = $aData[3]
    $Record = Join($aData, Chr(31))	; Chr(31) is ASCII US - Unit Separator
    $ = WriteProfileString('.\hash.ini', $Manager, $User, $Record)
  Else
    $Row = -1     ; no more data - exit the loop
  EndIf
 
  $Row = $Row + 1
Loop

Function xlFile($_ID, $_FN, $_File)

Dim $_

Select
Case $_FN = 0 ; Open
If Exist($_File) ; if the file exists, open it
;$_ = $_ID.Open($_File, $_Links, $_RO, $_Fmt)
$_ = $_ID.WorkBooks.Open($_File)
Exit @ERROR
Else
Exit 2 ; otherwise complain that is isn't found
EndIf

Case $_FN = 1 ; Save(as)
; If the file was previously saved (or opened), just re-save it,
; otherwise do a Save As
If Not $_ID.ActiveWorkbook.Path
$_ = $_ID.ActiveWorkbook.SaveAs($_File)
Else
$_ = $_ID.ActiveWorkbook.Save
EndIf
Exit @ERROR

Case $_FN = 2 ; SaveAs
$_ = $_ID.ActiveWorkbook.SaveAs($_File)
Exit @ERROR

EndFunction

Function xlRangeValue($_ID, $_Range, OPTIONAL $_Value, OPTIONAL $_Sheet)

$_Sheet = IIf($_Sheet = '', $_ID.ActiveSheet.Name, $_Sheet)

If VarType($_Value) <> 0
$_ID.WorkSheets($_Sheet).Range($_Range).Value = $_Value
Else
$xlRangeValue = $_ID.WorkSheets($_Sheet).Range($_Range).Value
EndIf

Exit @ERROR

EndFunction


Gargoyle
(MM club member)
2007-09-27 12:45 AM
Re: Need a script that read/collect and creates...

Dim $Users[UBound($Managers),0] give the error: array reference out of bounds!.

Try it this way
Dim $Count3,$Users[]
$Count3 = Ubound($Managers)
ReDim $Users[$Count3,0]


Glenn BarnasAdministrator
(KiX Supporter)
2007-09-27 12:49 AM
Re: Need a script that read/collect and creates...

 Originally Posted By: 1984
Not meaning to be served "silver-platter" codes, but would like feedbacks that I could understand and learn :-)

Didn't imply that you were, just indicating that you'd have to add some of your own brain power to it. ;\)

I'll look at it after dinner and see what's up.

G-


Glenn BarnasAdministrator
(KiX Supporter)
2007-09-27 05:32 AM
Re: Need a script that read/collect and creates...

Actually, we found a possible bug in how the variant arrays are handled by Kix. I have updated the UDF referenced above to work around the problem. It now returns an array of arrays when more than one row is specified. I'll post some sample code in the morning that uses the updated UDF.

Glenn


Glenn BarnasAdministrator
(KiX Supporter)
2007-09-27 05:49 AM
Re: Need a script that read/collect and creates...

This should get you started reading your Excel file - make sure you download the latest xlLib from the page referenced by my earlier post near the top of this thread.

This script module creates the HASH.INI file from data in the spreadsheet - part 2 of the code I posted earlier can enumerate this INI file and generate the CSV files, one for each manager.

I've used your data and confirmed that the HASH.INI file is created as expected using this script.

Glenn

 Code:
;; KixGenerated: 2007/09/26 - 19:54:31
Break On

;Working with Excel, for example

; Define an Excel object pointer
$oXL = xlInstantiateApp()
 
; Open the file
xlFile($oXL, 0, 'c:\temp\test.xls')
'Open: ' @SERROR ?
 
; Return an array of 4 values from the first data row
; Start with row 2, since row 1 has titles
; keep reading until a blank row is returned
$Row = 2

While $Row > 0
  $Range = 'A' + CStr($Row) + ':D' + CStr($Row)
  $aData = xlRangeValue($oXL, $Range, , 'Sheet1')
For Each $ in $aData
 $ ?
Next

  ; The first element of the array contains the user, fourth has the manager
  ; Howard Bullok has a great Hash UDF that would work well here, but 
  ; I'm going to use a "poor-man's" hash - an INI file, and reduce the number
  ; of UDFs required

  If $aData[0]
    ; Anti-Golf to make it clear what data goes where
    $User = $aData[0]
    $Manager = $aData[3]
    $Record = Join($aData, Chr(31))
    $ = WriteProfileString('.\hash.ini', $Manager, $User, $Record)
  Else
    $Row = -1     ; no more data - exit the loop
  EndIf

  $Row = $Row + 1
Loop


Richard H.Administrator
(KiX Supporter)
2007-09-27 01:56 PM
Re: Need a script that read/collect and creates...

 Originally Posted By: 1984
Richard:
Nothing happens!


Well, I tested it (again) and it works fine.

Are your files comma (",") delimited?
Did you run the script from the command line?
Are there 4 fields on each line as in your example?

Here is the script again, but with a little more debugging information:
 Code:
Break ON

$=SetOption("Explicit","ON")
Dim $fh,$sFile,$sLine

$fh=FreeFileHandle()
$sFile=".\data.csv"

If Not Open($fh,$sFile)
	$sLine=ReadLine($fh)
	While Not @ERROR
		"Processing line: "+$sLine+@CRLF
		$sLine=SPlit($sLine,",")
		If UBound($sLine)=3
			$=RedirectOutput($sLine[3]+".csv")
			Join($sLine,",")+@CRLF
			$=RedirectOutput("")
		Else
			"ERROR: Number of fields on this line <> 4"+@CRLF
			Exit 1
		EndIf
		$sLine=ReadLine($fh)
	Loop
Else
	"Cannot open "+$sFile+" for reading"+@CRLF
EndIf


Witto
(MM club member)
2007-09-27 06:15 PM
Re: Need a script that read/collect and creates...

As far as I can see, 1984 says the files are semicolumn (";") delimited
 Originally Posted By: 1984

 Code:
userX;UnitA;Paris;ManA
user54;Unit34;London;ManF



1984
(Starting to like KiXtart)
2007-09-28 12:45 AM
Re: Need a script that read/collect and creates...

Now we talking :-)

Performed quick test.

Glenn your code works now, although it miss delimiter ";" in created hash file...

Richard your code now works perfectly, dont know if you changed anything..

Gargoyle unfortunately I cannot make your code work, it still give same error; array reference out of bounds! even when changed to your latest suggestion

Wittos your code is actually the one which matches my need best, the only problem is that you manually enter "managers", which in my case means manually entering more the 50 managers in the code. If we could have a step before that filter out the managers and then populate the lists as in your code, then the circle would be closed and my need fulfilled!

To all, I also found that when I saved the the original Excel file as csv with comma delimited, it actually saves the file with semicolon ";" and not comma ",". I saw that when I opened it with notepad ++.

Now back to more testing/learning :-)


Witto
(MM club member)
2007-09-28 09:24 AM
Re: Need a script that read/collect and creates...

What is your original file?
  • Excel
  • Text with semicolumns

If it is Excel, I would try to recurse the D column from the last cell up to the top (or the first cell with a manager name) and gather all the manager names in an array.
If it is Semicolumn separated text, I would look to the code Richard provided.


1984
(Starting to like KiXtart)
2007-09-28 03:19 PM
Re: Need a script that read/collect and creates...

The original scenario was based on Excel file and your code seems best matching my need.

Can you please explain what you mean by; recurse the D column from the last cell up to the top (or the first cell with a manager name) and gather all the manager names in an array.

Do you mean to filter out managers in Excel to get a list of all managers?

How do I gather all the manager names in an array in execl?


Glenn BarnasAdministrator
(KiX Supporter)
2007-09-28 04:17 PM
Re: Need a script that read/collect and creates...

If you look at the script I posted, you'll see that the INI file creates a section for each manager ([MGRA]) and then lists each user's information as a record in that section. I chose to use an INI file because it is VISUAL - you can see how your data is organized. This has many benefits, especially during development of complex processes - you can see how the data is organized, how your code is interpreting results, and how the logic is handling issues like missing fields.

Of course there are alternatives - one is to enumerate your list and find all the manager IDs, collected into an array. You can then use Sort() and Uniq() to change that to an array of unique manager names. Then create a 2-eimension array - the first dimension size is the number of managers, the second is the maximum number of users assigned to a manager.

Then, you can enumerate your data again. Get the MgrID, use AScan to change it to an ID # (the record in the list of managers) and use that as the first pointer to the data array...

Whew!! My point is that you can write complex code and do it all in memory, or you can use the INI file as a disk based array that will permit access by name. Much easier, especially for someone new to coding, usnig arrays, etc.

The second code example that I posted earlier will generate CSV files for each manager, with that manager's users as the data. I used Chr(31) as a delimiter, which is unlikely to conflict with any text in your data. The example will work no matter how you generate the INI file - excel or text file source.

Glenn


Witto
(MM club member)
2007-09-28 04:38 PM
Re: Need a script that read/collect and creates...

 Code:
$RC = $objExcel.Range("A1").End($xlDown).End($xlToRight).Select

this leads you to the last cell in your range
I presume the column is always D
You can get the row like this
 Code:
...
Dim $Row
...
$Row = $objExcel.ActiveCell.Row
...

I presume the first cell with a manager in it is always 2
So I would go from the last cell in column D to the second
Anyway, here is some code
;*************************************************************************
;  Script Name:  
;  Author:        Wim Rotty
;  Date:          26/09/2007
;  Description:   Copy and paste data from one Excel book to other books
;*************************************************************************
;Script Options

If Not @LOGONMODE
   Break On
Else
   Break Off
EndIf
Dim $RC
$RC = SetOption("Explicit", "On")
$RC = SetOption("NoMacrosInStrings", "On")
$RC = SetOption("NoVarsInStrings", "On")
If @SCRIPTEXE = "KIX32.EXE"
   $RC = SetOption("WrapAtEOL", "On")
EndIf

;Declare variables
Dim
 
$MyTable
Dim $objExcel
Dim $xlDown, $xlToLeft, $xlToRight, $xlUp
Dim $Row, $i, $Manager, $Managers[0], $j

;Initialize variables
$MyTable = "C:\Test\Tabel.xls"
$objExcel = CreateObject("Excel.Application")
If @ERROR
   Exit @ERROR
EndIf
$xlDown = -4121
$xlToLeft = -4159
$xlToRight = -4161
$xlUp = -4162
$j = 0

;Code
$objExcel.Visible = -1
$RC = $objExcel.Workbooks.Open($MyTable)
$RC = $objExcel.Selection.Autofilter
$RC = $objExcel.Range("A1").End($xlDown).End($xlToRight).Select
$Row = $objExcel.ActiveCell.Row
For $i = $row to 2 step -1
   
$Manager = $objExcel.Range("D"+$i).Text
   
If AScan($Managers, $Manager) = -1
       
ReDim Preserve $Managers[$j]
       
$Managers[$j] = $Manager
        $j = $j + 1
   
EndIf
Next
$RC = $objExcel.Range($objExcel.Selection, $objExcel.Cells(1)).Select
For Each $Manager in $Managers
    $RC = $objExcel.Selection.AutoFilter(4, $Manager)
   
$RC = $objExcel.Selection.Copy
    $RC = $objExcel.Workbooks.Add
    $RC = $objExcel.ActiveSheet.Paste
    $RC = $objExcel.ActiveWindow.ActivateNext
Next
$RC = $objExcel.Selection.AutoFilter(4)

;Personal UDF Section

;UDF Section


1984
(Starting to like KiXtart)
2007-09-28 06:01 PM
Re: Need a script that read/collect and creates...

What can I say! Just beautiful! :-)

Witto your code is exactly what I looked for. I am very very grateful for your help and feedback. You have my 5 star!

It does exactly what I wanted and tried to state with this post.

A last wondering to make the hole process complete:

How do we filter out (remove) the managers form each new created list, and name each new created list after the manager the list belong to, instead of book1, book2 book3.....

That would make the hole process full automated!
:-)


Witto
(MM club member)
2007-09-28 06:56 PM
Re: Need a script that read/collect and creates...

A part of the code is made using the macro recorder
I will try to give an example
  • Start MS Excel
  • Start the Macro Recorder via Tools --> Macro --> Record new macro...
  • Do a File --> Save As and give the file a name
  • Stop the macro recorder
  • Go to Tools --> Macro --> Macros
  • Start editing the recorded macro
  • Now you have to be a littlebit inventive and decide what you really need in this code and how you can paste this in your KiX script. Anyway, you learned you will need ActiveWorkbook.SaveAs

Maybe you also want to get rid of annoying messages telling that you will overwrite files. Google is your friend
http://www.google.be/search?hl=nl&q=ActiveWorkbook.SaveAs+site%3Amicrosoft.com&meta=
First hit
http://support.microsoft.com/kb/213641
Silver platter with some explanation
;*************************************************************************
;  Script Name:     FindManagers.kix
;  Author:         Wim Rotty
;  Date:             26/09/2007
;  Description:     Copy and paste data from one Excel book to other books
;*************************************************************************
;Script Options

If Not @LOGONMODE
    Break On
Else
    Break Off
EndIf
Dim $RC
$RC = SetOption("Explicit", "On")
$RC = SetOption("NoMacrosInStrings", "On")
$RC = SetOption("NoVarsInStrings", "On")
If @SCRIPTEXE = "KIX32.EXE"
    $RC = SetOption("WrapAtEOL", "On")
EndIf

;Declare variables
Dim
 
$MyTable
Dim $objExcel
Dim $xlDown, $xlToLeft, $xlToRight, $xlUp
Dim $Row, $i, $Manager, $Managers[0], $j

;Initialize variables
$MyTable = "C:\Test\Tabel.xls"
$objExcel = CreateObject("Excel.Application")
If @ERROR
    Exit @ERROR
EndIf
$xlDown = -4121
$xlToLeft = -4159
$xlToRight = -4161
$xlUp = -4162
$j = 0

;Code
;Do not show alerts like messages about overwriting files

$objExcel.DisplayAlerts = False
;Show Excel, not really needed if you quit at the end
;$objExcel.Visible = -1
;Open file

$RC = $objExcel.Workbooks.Open($MyTable)
;Add filter
$RC = $objExcel.Selection.Autofilter
;Select cell at bottom right of data range
$RC = $objExcel.Range("A1").End($xlDown).End($xlToRight).Select
;Get cell rownumber
$Row = $objExcel.ActiveCell.Row
;Recurse cells up to cell 2 and gather all the Manager names in an array
For $i = $row to 2 step -1
   
;Get the text (manager name) in the cell
    $Manager = $objExcel.Range("D"+$i).Text
   
;Is the manager name NOT in the array?
    If AScan($Managers, $Manager) = -1
       
;If not, add location to array and add it to new location
        ReDim Preserve $Managers[$j]
       
$Managers[$j] = $Manager
        $j = $j + 1
   
EndIf
Next
;Select all data in range
$RC
 = $objExcel.Range($objExcel.Selection, $objExcel.Cells(1)).Select
;Recurse the Managers array
For Each $Manager in $Managers
    ;Filter for each manager name
    $RC = $objExcel.Selection.AutoFilter(4, $Manager)
   
;Copy the selection to the clipboard
    $RC = $objExcel.Selection.Copy
    ;Add a new workbook
    $RC = $objExcel.Workbooks.Add
    ;Paste the data from the clipboard
    $RC = $objExcel.ActiveSheet.Paste
    ;Select the D column with the manager name
    $RC = $objExcel.Columns("D:D").Select
    ;Clear all in this column
    $RC = $objExcel.Selection.Clear
    ;Save the workbook with as name the manager
    $RC = $objExcel.ActiveWorkbook.SaveAs(@SCRIPTDIR+"\"+$Manager+".xls",,,,,False)
   
;The next active sheet is the original file
    $RC = $objExcel.ActiveWindow.ActivateNext
Next
;Close Excel
$RC = $objExcel.Application.Quit

;Personal UDF Section

;UDF Section


Witto
(MM club member)
2007-09-29 09:38 AM
Re: Need a script that read/collect and creates...

 Originally Posted By: 1984
Can you please explain what you mean by; recurse the D column from the last cell up to the top (or the first cell with a manager name) and gather all the manager names in an array.
Do you mean to filter out managers in Excel to get a list of all managers?
Recursion From Wikipedia, the free encyclopedia
 Originally Posted By: Wikipedia
Recursion is the process a procedure goes through when one of the steps of the procedure involves rerunning the entire same procedure.
I wanted to say look at every manager name in te D column, see if it is the first time you read the name and if yes, put it in a collection or array

 Originally Posted By: 1984
How do I gather all the manager names in an array in execl?
Array From Wikipedia, the free encyclopedia
 Originally Posted By: Wikipedia
In computer science an array is a data structure consisting of a group of elements that are accessed by indexing.
I just wanted to say an array in KiXtart, not in Excel VBA.


1984
(Starting to like KiXtart)
2007-09-29 08:45 PM
Re: Need a script that read/collect and creates...

Aha thats what "recursion" means!... slowly beginning to understand how it works on high level. Also the "macro recording" didn't know such function even exist.

Gotta admit my knowledge is very limited when it comes to coding and understanding all definitions surround it. its comparable to my English .-)

Anyway, your silver platter code is just beautiful :-) and ofcurse Kix is the king.

I realize that those few times I make codes I have problem with understanding the definition and use of "array". Thats something I always need to refresh, before I can make an script work...
It gets much more difficult when other language gets involved in the case scenario, like VBs, as I know nothing about it.

In our case here, I still have some wondering that I couldn't figure out.

You are using variables which I cannot figure out what they really represent and do, and how you get their values:

 Code:
$xlDown = -4121 
$xlToLeft = -4159 
$xlToRight = -4161 
$xlUp = -4162 


I have played with macros in Excel. I of course need now to adapt your code to the Excel list I have (the big one), but found its not that easy as it looked in first place:

For adapting the code to the actual Excel list I change the following in the script:

 Code:
$Manager = $objExcel.Range("D"+$i).Text
$RC = $objExcel.Columns("D:D").Select

I changed "D" to "K" in these line, that is the column of managers


I changed "D" to "K", The original Excel list I have contains 14 columns (the last one is "N"). The first column "A" presents the User IDs, followed by lots of user contact information, and then column "K" represents the managers, followed by managers contact data.

its about 1000 users, and 50 managers. some few also don't have a managers assigned on them so for those the managers column is empty.

I'm going now to switch to excel 2003 instead of 2007, see if its easier to understand how i can benefit from macro recorder, maybe I succeeded adapt your code to the big Excel file.


Witto
(MM club member)
2007-09-30 05:06 PM
Re: Need a script that read/collect and creates...

 Originally Posted By: 1984
You are using variables which I cannot figure out what they really represent and do, and how you get their values
 Code:
$xlDown = -4121 
$xlToLeft = -4159 
$xlToRight = -4161 
$xlUp = -4162

Nothing to understand about, just take it because they are like that. In fact those numbers are constants. See the link in my first post.
Microsoft Excel Constants (Excel 2003 VBA Language Reference)


Glenn BarnasAdministrator
(KiX Supporter)
2007-09-30 05:36 PM
Re: Need a script that read/collect and creates...

1984:

I'm about to post my xlLib UDF, which will make working with Excel a breeze. I'm also going to post a script that exercises / demonstrates how to use each of the functions in the library. You might want to hold off for a few hours... It's Sunday - supposedly a day of rest and relaxation for most of us. ;\)

Glenn


1984
(Starting to like KiXtart)
2007-10-01 12:46 AM
Re: Need a script that read/collect and creates...

rest? what rest... heheh... no rest for me -:) almost forgot there is relaxing days ... "have" to keep damn deadlines...

For me, you are wonderful people helping others around the globe freely... sometimes makes one believe in mankind..

Wish you happy relaxing day, and all the credits to you and kix!

/CY


1984
(Starting to like KiXtart)
2007-10-01 12:52 PM
Re: Need a script that read/collect and creates...

Witto, can you explain this row:

$RC = $objExcel.Selection.AutoFilter(4, $Manager)

What does the figure "4" doing?


Glenn BarnasAdministrator
(KiX Supporter)
2007-10-01 01:18 PM
Re: Need a script that read/collect and creates...

 Quote:
You are using variables which I cannot figure out what they really represent and do, and how you get their values:


Go to msdn.microsoft.com and search for "excel constants" - this should return a list of pages - the first one of them will bring you to a page that defines each of the constants and their values. Each value has a specific meaning, as you will see. The page I'm looking at is http://msdn2.microsoft.com/en-us/library/aa221100(office.11).aspx.

When programming in VB, there are include files that define readonly vars with these values, thus they are "constants". The only way to simulate this in Kix is to declare them as globals, but they won't be read-only. This way, you use the constant name instead of the number, which makes reading the source code much easier. I thought about adding some commonly used values as Globals in my xlLib UDFs, but wasn't sure of the impact of so many vars. Maybe after more testing.

Anyway, that's where these weird numbers come from... (and how you can figure out what they mean and where to use them)

Glenn


1984
(Starting to like KiXtart)
2007-10-01 01:38 PM
Re: Need a script that read/collect and creates...

Ok thanx for the wired number explanation Glenn,

BTW,
To make it easier for me to work with the big list, I limited the list to 5 column A-E. The last column "E" contains empty cells, with a data formula where I can chose "Active" or "Inactive" text as "Status" for each user in column "E". Note the column cells are empty.

 Code:
A	B	C	D	E
ID:	Unit:	Site:	Manager:	Status:



Im still using Wittos code, would be happy to see how your xlib codes could help me out in my case. :-)


Glenn BarnasAdministrator
(KiX Supporter)
2007-10-01 01:46 PM
Re: Need a script that read/collect and creates...

I've got a full load of work this morning, so can't get into the details for a while, but simply:

 Code:
Call '.\xlLib.udf'

; Launch Excel
$oXL=xlInit()

; open file
xlFile($oXL,'myfile.xls',0) 

; sort - define the range containing your data, "D1" is the column with
; the manager's name, "A1" contains the user's name - this sorts
; by manager, then by user
xlRangeSort($oXL, 'A1:E6', 'D1',1,'A1',1)

; Return the sorted data in an array - 6 rows of 5 columns in this case
$aData = xlRangeValue($oXL, 'A1:E6')

; Enumerate the data - 2 dimension array
; $aData[0][3] is the manager's name of the first row of data
$Managers = 'mgra','mgrb','mgrc'
For each $Manager in $Managers
  For $I = 0 to UBound($aData)
    If $aData[$I][3] = $Manager
      ; Have data for current manager
      ; write data to manager file
      $ = RedirectOutput($Manager + '.csv')
      ; convert entire row to CSV format - don't forget to include the 
      ; CSV() UDF file.
      CSV($aData[$I]) ?
      $ = RedirectOutput('')
    EndIf
  Next
Next

xlQuit($oXL)


All Excel interaction is handled with just 6 xlLib calls...

This is untested, and needs to be adapted to your file names, data, data ranges, etc.. but should work with a little effort. It will create separate .CSV files for each manager, with the manager's data in each file.

When you define range for the sort and value calls, only specify the range with data, do not include the headers!

Download the Zip file and play with the test script to see how everything works.

Glenn


1984
(Starting to like KiXtart)
2007-10-01 03:39 PM
Re: Need a script that read/collect and creates...

Great Glenn,
I got the zip, I play around, see what can achive.

Thanx a lot
/CY


Witto
(MM club member)
2007-10-01 06:16 PM
Re: Need a script that read/collect and creates...

 Originally Posted By: 1984
Witto, can you explain this row:
$RC = $objExcel.Selection.AutoFilter(4, $Manager)
What does the figure "4" doing?

You should use the Macro recorder and edit the code you recorded.
If you would do so, you would notice after adding an autofilter, starting the recorder and recording the selection of "ManA" in column D, the recorder recorded this code for you:
 Code:
    Selection.AutoFilter Field:=4, Criteria1:="ManA"

4 points to the fourth column in your autofilter


1984
(Starting to like KiXtart)
2007-10-01 08:29 PM
Re: Need a script that read/collect and creates...

Ok dudes, here we go:

At last, thanx to all the feedbacks and help, I managed to adapt Wittos code to get what I needed. Its tested with Excel 2007 and works based on my needs as earlier stated in this topic.

As Witto suggested Im using Macro recorder in Excel to obtain the VB codes.


 Code:
;*************************************************************************
;  Script Name:     FindManagers.kix
;  Author:         Wim Rotty
;  Date:             26/09/2007
;  Description:     Copy and paste data from one Excel book to other books
;*************************************************************************
;Script Options
If Not @LOGONMODE
    Break On
Else
    Break Off
EndIf
Dim $RC
$RC = SetOption("Explicit", "On")
$RC = SetOption("NoMacrosInStrings", "On")
$RC = SetOption("NoVarsInStrings", "On")
If @SCRIPTEXE = "KIX32.EXE"
    $RC = SetOption("WrapAtEOL", "On")
EndIf

;Declare variables
Dim $MyTable
Dim $objExcel
Dim $Row, $i, $Manager, $Managers[0], $j

;Initialize variables
$MyTable = "C:\Test\Tabel.xls"
$objExcel = CreateObject("Excel.Application")
If @ERROR
    Exit @ERROR
EndIf

$j = 0

;Code
;Do not show alerts like messages about overwriting files
$objExcel.DisplayAlerts = False
;Show Excel, not really needed if you quit at the end
;$objExcel.Visible = -1
;Open file
$RC = $objExcel.Workbooks.Open($MyTable)
;Add filter
$RC = $objExcel.Selection.Autofilter
;Select data range (cell at bottom right of data range)
$RC = $objExcel.Range("A1:P1285")
;Get cell rownumber
$Row = $objExcel.ActiveCell.Row
;Recurse cells up to cell 2 and gather all the Manager names in an array
For $i = $row to 2 step -1
    ;Get the text (manager name) in the cell
    $Manager = $objExcel.Range("K"+$i).Text
    ;Is the manager name in the array?
    If AScan($Managers, $Manager) = -1
        ;If not, add location to array and add it to new location
        ReDim Preserve $Managers[$j]
        $Managers[$j] = $Manager
        $j = $j + 1
    EndIf
Next
;Select all data in range
$RC = $objExcel.Range($objExcel.Selection, $objExcel.Cells(1)).Select
;Recurse the Managers array
For Each $Manager in $Managers
    ;Filter for each manager name (where "11" is the number of manager column)
    $RC = $objExcel.Selection.AutoFilter(11, $Manager)
    ;Copy the selection to the clipboard
    $RC = $objExcel.Selection.Copy
    ;Add a new workbook
    $RC = $objExcel.Workbooks.Add
    ;Paste the data from the clipboard
    $RC = $objExcel.ActiveSheet.Paste
         ;Select columns 
	 $RC = $objExcel.Columns("D:O").Select
         ;Hide selected columns 
	 $objExcel.Selection.EntireColumn.Hidden = True 
         ;AutoFit columns
	 $RC = $objExcel.Columns("A:C").EntireColumn.AutoFit
    ;$RC = $objExcel.Selection.EntireColumn.Hidden
    ;Save the workbook with as name the manager
    $RC = $objExcel.ActiveWorkbook.SaveAs@SCRIPTDIR+"\"+$Manager+".xls",,,,,False)
    ;The next active sheet is the original file
    $RC = $objExcel.ActiveWindow.ActivateNext
Next
;Close Excel
$RC = $objExcel.Application.Quit

;Personal UDF Section

;UDF Section



5 star to Witto and Glenn for all their help and patience.

/CY


Witto
(MM club member)
2007-10-02 12:02 AM
Re: Need a script that read/collect and creates...

Just some questions at first glance
 Code:
;Select data range (cell at bottom right of data range)
$RC = $objExcel.Range("A1:P1285")
Is your excel sheet always 1285 rows deep?

 Code:
    ;Save the workbook with as name the manager
    $RC = $objExcel.ActiveWorkbook.SaveAs@SCRIPTDIR+"\"+$Manager+".xls",,,,,False)
I think you missed a "(" here:
$RC = $objExcel.ActiveWorkbook.SaveAs(@SCRIPTDIR+"\"+$Manager+".xls",,,,,False)

Have you tested your code while editing your script? As far as I can see and as far as I could test your script, you did not select anything so there wasn't anything to copy to the clipboard.

Maybe KiXtarter can help you to run your script from time to time while you are writing it.


1984
(Starting to like KiXtart)
2007-10-02 12:42 AM
Re: Need a script that read/collect and creates...

 Originally Posted By: Witto

 Code:
;Select data range (cell at bottom right of data range)
$RC = $objExcel.Range("A1:P1285")
Is your excel sheet always 1285 rows deep?

In this particular case, yes, this Excel list is "always" 1285 rows deep.
Anyway that was the only way I could make it work with the complete data range.

 Originally Posted By: Witto

I think you missed a "(" here:
$RC = $objExcel.ActiveWorkbook.SaveAs(@SCRIPTDIR+"\"+$Manager+".xls",,,,,False)

Correct. Dont know how it was missed.

Note, in this case the Excel list is in 2007 format xlsx. When saving the new workbooks I chose to save them in XP/2003 compatible file format, using FileFormat values "56" (xlExcel8).
 Code:
$RC = $objExcel.ActiveWorkbook.SaveAs(@SCRIPTDIR+"\"+$Manager+".xls",56,,,,False)

The code is working fine for me, anyway I will check the kixtarter too.


Witto
(MM club member)
2007-10-02 12:58 AM
Re: Need a script that read/collect and creates...

I am using Office 2003.
I think you should use .Select here:
$RC = $objExcel.Range("A1:P1285").Select


1984
(Starting to like KiXtart)
2007-10-04 02:32 PM
Re: Need a script that read/collect and creates...

Witto could you validate this one?. Works fine for me with Excel 2003.

In this case scenario the source Excel book contains 14 columns (A:P).
Managers column is "L".

 Code:

;*************************************************************************
;  Script Name:     FindManagers.kix
;  Author:          Wim Rotty
;  Date:            26/09/2007
;  Update by:       1984 /CY
;  Description:     Read, sort and filter data from an Excel book, 
;                   then create new book And Copy/paste data to it.
;*************************************************************************

;Script Options
If Not @LOGONMODE
    Break On
Else
    Break Off
EndIf
Dim $RC
$RC = SetOption("Explicit", "On")
$RC = SetOption("NoMacrosInStrings", "On")
$RC = SetOption("NoVarsInStrings", "On")
If @SCRIPTEXE = "KIX32.EXE"
    $RC = SetOption("WrapAtEOL", "On")
EndIf

;Declare variables
Dim $MyTable
Dim $objExcel
Dim $xlDown, $xlToLeft, $xlToRight, $xlUp
Dim $Row, $i, $Manager, $Managers[0], $j

;Initialize variables
$MyTable = "C:\Test\book1.xls"
$objExcel = CreateObject("Excel.Application")
If @ERROR
    Exit @ERROR
EndIf
$xlDown = -4121 
$xlToLeft = -4159 
$xlToRight = -4161 
$xlUp = -4162 
$j = 0

;Do not show alerts like messages about overwriting files
$objExcel.DisplayAlerts = False
;Show Excel, not really needed if you quit at the end
;$objExcel.Visible = -1
;Open file
$RC = $objExcel.Workbooks.Open($MyTable)
;Add filter
$RC = $objExcel.Selection.Autofilter
;Select cell at bottom right of data range
$RC = $objExcel.Range("A1").End($xlDown).End($xlToRight).Select
;Get cell rownumber
$Row = $objExcel.ActiveCell.Row

;Recurse cells up to cell 2 and gather all the Manager names in an array
For $i = $row to 2 step -1
    ;Get the text (manager name) in the cell (Column "L")
    $Manager = $objExcel.Range("L"+$i).Text
    ;Is the manager name NOT in the array?
    If AScan($Managers, $Manager) = -1
        ;If not, add location to array and add it to new location
        ReDim Preserve $Managers[$j]
        $Managers[$j] = $Manager
        $j = $j + 1
    EndIf
Next

;Recurse the Managers array, Filter for each manager name
For Each $Manager in $Managers
    ;Add AutoFilter for manager on column 12 (= L)
    $RC = $objExcel.Selection.AutoFilter(12, $Manager)
	 ;Select all data in range Column A to column P
	 $RC = $objExcel.Range($objExcel.Selection, $objExcel.Columns("A:P")).Select
    ;Copy the selection to the clipboard
    $RC = $objExcel.Selection.Copy
    ;Add a new workbook
    $RC = $objExcel.Workbooks.Add
    ;Paste the data from the clipboard
    $RC = $objExcel.ActiveSheet.Paste
	 ;Select Column E to P
	 $RC = $objExcel.Columns("E:P").Select
	 ;Hide column E to P
	 $objExcel.Selection.EntireColumn.Hidden = True 
	 ;Autofit visible columns (A to D)  
	 $RC = $objExcel.Columns("A:D").EntireColumn.AutoFit
    ;Save the workbook with as name the manager
    $RC = $objExcel.ActiveWorkbook.SaveAs(@SCRIPTDIR+"\"+$Manager+".xls",,,,,False)
    ;The next active sheet is the original file
    $RC = $objExcel.ActiveWindow.ActivateNext
Next

;Close Excel
$RC = $objExcel.Application.Quit

;Personal UDF Section



Witto
(MM club member)
2007-10-05 12:59 AM
Re: Need a script that read/collect and creates...

 Originally Posted By: 1984
;Add AutoFilter for manager on column 12 (= L)
column 12 is the 12th column of the filter. Per example: if the filter starts at column C, the 12th column is N
Looks nice I think. Changed it back to your first example and seems to work.