|
|
|||||||
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 |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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. |
||||||||
|
|
|||||||
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.
Microsoft Excel Constants (Excel 2003 VBA Language Reference) |
||||||||
|
|
|||||||
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. |
||||||||
|
|
|||||||
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/ |
||||||||
|
|
|||||||
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. |
||||||||
|
|
|||||||
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. |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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? |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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 :-) |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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] |
||||||||
|
|
|||||||
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- |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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 :-) |
||||||||
|
|
|||||||
What is your original file?
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. |
||||||||
|
|
|||||||
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? |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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
|
||||||||
|
|
|||||||
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! :-) |
||||||||
|
|
|||||||
A part of the code is made using the macro recorder I will try to give an example
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
|
||||||||
|
|
|||||||
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? 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. Originally Posted By: 1984 How do I gather all the manager names in an array in execl? Originally Posted By: Wikipedia In computer science an array is a data structure consisting of a group of elements that are accessed by indexing. |
||||||||
|
|
|||||||
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. |
||||||||
|
|
|||||||
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) |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
Witto, can you explain this row: $RC = $objExcel.Selection.AutoFilter(4, $Manager) What does the figure "4" doing? |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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. :-) |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
Great Glenn, I got the zip, I play around, see what can achive. Thanx a lot /CY |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
Just some questions at first glance Code: ;Select data range (cell at bottom right of data range) $RC = $objExcel.Range("A1:P1285") Code: ;Save the workbook with as name the manager $RC = $objExcel.ActiveWorkbook.SaveAs@SCRIPTDIR+"\"+$Manager+".xls",,,,,False) $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. |
||||||||
|
|
|||||||
Originally Posted By: Witto Code: ;Select data range (cell at bottom right of data range) $RC = $objExcel.Range("A1:P1285") 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. |
||||||||
|
|
|||||||
I am using Office 2003. I think you should use .Select here: $RC = $objExcel.Range("A1:P1285").Select |
||||||||
|
|
|||||||
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 |
||||||||
|
|
|||||||
Originally Posted By: 1984 ;Add AutoFilter for manager on column 12 (= L) Looks nice I think. Changed it back to your first example and seems to work. |