I have a column which contains productIDs which are similar to numbers
ProductIDS
46257547467
65464564656
47682542896
68683582757
I also converted it to text using =TEXT(cellNO,"0") and it works fine for that time. But next time after few hours when I open the file it reads that column as numbers like this:
ProductIDS
4.62E+10
6.54E+10
4.76E+10
6.86E+10
How can I permanently convert it to text so that when I open it every time it shows me the column as text ? Thanks.
It sounds like you're attempting to generate unique IDs within an Excel sheet (for use in another application, maybe...?). Using a formula here won't do much good if a) new rows are being added (particularly intermingled with existing rows), or b) the formula is based on the context of the sheet.
I've written a little sub that generates a unique ID for a given column, auto-populating it when something about that row gets populated. It works for a range of inserted rows too, not just the current row.
Private Sub Worksheet_Change(ByVal targetRange As Range)
' Confirm that the change is occuring where I want to track it
If targetRange.Column = Range("WhereChangeOccurs").Column Then
' Capture the target column holding the IDs
Dim IDRangeColumn As Integer
IDRangeColumn = Range("IDRange").Column
' Loop through each row of the target range, inserting an ID literal
For Each thisrow In targetRange.Rows
' update the ID with
' DateTime (to milliseconds) plus
' unique GUID based on system
Cells(thisrow.Row, IDRangeColumn).Value = Format(Now, "yyyy-mm-dd: hh.mm.ssss-") & Mid$(CreateObject("Scriptlet.TypeLib").GUID, 2, 18)
Next
End If
End Sub
It's pretty fast, and the uniqueness holds up even when inserting multiple rows (so far checked to about 50-100 rows at a time). This has the benefit of always generating a unique ID for a row, without needing Copy-Paste-Values; no human intervention required.
Note that the ", 18)" in the ID generation can be a longer number if you'd rather use that for uniqueness; I wanted something readable (date/time) at the beginning simply for human understandability.
Related
I have a form that is supposed to show the total sum of different numeric values between two dates, a start date and a finish date. For this, I thought the best option would be to use the SumIfs WorkSheetFunction. However, after trying to code this, the function is not working properly. I am not sure of what is wrong. If I type the exact same formula on the worksheet that has the table with my sample data, it works perfectly.
So, the form I designed is the following:
A second label and textbox will be added for the finish (or end) date. However, I thought it would be better to do that once I get the code to work with a single date in the beginning. The textbox where the user will insert the start date is called tbxDate and the textbox that will show the resulting sum is called tbxBalance. The button that triggers the SumIfs functions is called cmdCalculate.
Also, the table that stores the data (which only has one row of data so far for testing purposes) is this one:
The table name is Sales, and the worksheet name is SalesWS. I thought the code should be pretty simple, unless there is something I am missing. What I did was:
Private Sub cmdCalculate_Click()
Set SalesRange = Worksheets("SalesWS").Range("Sales[TOTAL]")
Set DatesRange = Worksheets("SalesWS").Range("Sales[DATE]")
tbxBalance = Application.WorksheetFunction.SumIfs(SalesRange , DatesRange , ">=" & tbxDate)
End Sub
The issue is that the >= part of the criteria is failing. I only get proper results using only the greater than or less than conditions. For example, if I enter the date 09/08/2020 in the textbox the result in the balance textbox is 0, but if I enter the date 08/08/2020 or anything before it works. It just ignores the condition to sum the values if the date is equal to what is entered. It only works with dates greater or less than what the user inputs in the textbox, excluding the chosen date.
I already checked that the column with the dates in the table is formatted properly.
The version of your code given below should work provided your DATE range contains true dates and tbxDate contains a string VBA can recognise as a date.
Private Sub cmdCalculate_Click()
Dim Fun As Double
Set SalesRange = Worksheets("SalesWS").Range("Sales[TOTAL]")
Set DatesRange = Worksheets("SalesWS").Range("Sales[DATE]")
Fun = Application.WorksheetFunction.SumIfs(SalesRange, DatesRange, ">=" & CLng(CDate(tbxDate.Value)))
tbxBalance = Format(Fun, "#,##0.00")
End Sub
Remember that tbxBalance will cotnain a text string, not a number. Use Excel's NUMBERVALUE function to convert the formatted number you have in tbxBalance after the above code back to a number you can calculate with.
I would like to find the text "Currency" in columns A or B, store all the currencies listed under Currency. Same process for Amount (Can be in an column)
Store values in an array. Then paste in Output Sheet. The currencies will already be listed in Output sheet in 1st row of the sheet. However if it is a new currency then the code should find last used cell in row 1 and add it. The value of Amount should be added to Output sheet against the currency and ID number also copied from the Source sheet.
I have some code.
Public Sub loopRow()
Dim curArray As Variant
Dim listarray As Variant
Dim cnt As Long
'Find Currency
Dim rgFound As Range
Set rgFound = Range("A:B").Find("Currency")
'Find last used row
curArray = Cells(rgFound.Address).End(xlUp).Row
'Transpose list of currecny from the row down from the word Currency that it has found
listarray = Application.Transpose(Cells(Rows, curArray).End(xlUp)).Row
For cnt = LBound(curArray) To UBound(curArray)
curArray(cnt) = curArray(cnt)
Next cnt
For cnt = LBound(curArray) To UBound(curArray)
'Debug.Print curArray(cnt)
'Copy and paste into Sheet under the correct curreny, if new currency then add this in row A
Next cnt
End Sub
Whilst you need to understand your question is unanswerable as is, I'll do my best to help.
The problem we have is not seeing the source sheet the way you do, as we can't see it at all. You say you have the word Currency in columns A or B or both, and an ID column somewhere, and Amount values everywhere. That's tricky source data. If as is more likely, the ID is in a specific column and the amounts are in a set of columns, then we'd have a chance.
Your question outlines the basic steps you'd want to take pretty well, so you're off to a good start.
However you can do all of the work without VBA, certainly if I'm right about the Source data. Create yourself a working sheet, or multiple working sheets. Definitely one to sort out the full list of currencies. Grab a copy of columns A and B (by formulae) and then have the working sheet go through line by line and use logic to build the list. Spreadsheets are great at this.
Once you have the list, use it as row headers on your Output sheet and use sumifs to get the values. I am not sure how the IDs would fit in, but if they were to be your row headings, then do the same as the above to get the list of unique ids and link them into your Output page in column A. Your sumifs can handle that.
That will hardly tell you all you need to know, but if you work it out you'll have learned a lot about Excel and when you need to go into VBA.
If you'd rather do it with VBA, break down each step until it works, and then go onto the next one.
And if you want more help, paste your data in here. Anonymise it first if you need to.
I am trying to store all the values of an excel column in an array.
set rangeDate to {value of range "A14:A100"}
repeat with date in rangeDate
if (date as string is equal to "01/01/2001") then
log "It works"
end if
end repeat
In my Excel I do have an exact date of 01/01/2001 formatted in the specified columns. When I remove the range and it is just cell A14 (where the date is) it works. But when I include the range A14:A100 it doesn't work.
I am new to applescript, I guess that it doesn't store the values as array values and instead a string object? Any help would be appreciated
You have 4 issues :
1) value of range should not be between {}, but between ()
2) 'Date' is a reserved word in Applescript, so you should not use it as the variable in the loop. I replaced it with 'myDate'.
3) instead of converting your date to string to compare with "01/01/2001", it is quicker to keep comparing 2 dates, and then, compare with the date "01/01/2001"
4) I think it is a bug (at least with my Excel version), but the rangeDate variable is not a list of dates as expected, but for me a list of list : {{01/02/01},{02/02/01},………} Therefore, each member of 'rangeDate' is not a date, but a list made on one item which is a date ! I am not sure, but it could also be that range definition could be a list of ranges... So I am using item 1 of sub list.
Anyway, script bellow is working :
tell application "Microsoft Excel"
activate
tell active sheet of document 1
set rangeDate to (value of range "A14:A100")
repeat with mydate in rangeDate
set TheDate to item 1 of mydate
if TheDate = (date "lundi 1 janvier 2001 00:00:00") then
log "It works"
end if
end repeat
end tell
end tell
Quickly getting the values of a range of cells is great news! But even better is that you can fill in the values of a range by defining the value of that range. This is SO MUCH FASTER than doing it one cell at a time.
When I tried getting the value of a column (a range of cells), I received a list of lists. Each item in the list had only one value - that is the value of the cell.
To speed up complex operations, once you've got the list of values, take the process out of the "tell Excel" block and let AppleScript do the calculations. Then turn the result back into a list of lists and define the value of the range in Excel.
I had a problem reading ranges with some cells containing #VALUE! (failed formulas). I didn't find a solution on the Internet, so I thought it would be a good idea to share my solution here. Comments & improvement are surely welcome. I'm inclined to think there is a more straightforward solution to the problem than this. :)
Getting all values with value of range can lead to a problem messing up the output of the script. AppleScript doesn't consider a cell's content "#VALUE!" (= missing values) a value since it is, well, missing. Therefore the script doesn't include the cell's content in the list of values. This obviously messes up the cell order in the values list, since it has less items than the actual range has cells. In this situation it is quite impossible to return each value to its original cell in the workbook. Adding ”of ranges” to the code includes all cells with missing values solving the problem.
N.B. The values will be displayed as a one-dimensional array. Handling multi-column ranges requires more work. Nonetheless the missing values are included.
set celVals to (value of ranges of range "A1:A4")
E.g. {2.2.2022, 1.1.2011, missing value, 3.3.2033}
In order to return the values back to the workbook it is required to build back the list of lists. A missing value will be written to its cell as an empty string. Of course the original (failed) formula can be written instead, if needed.
N.B. again. This code applies to one column situation only. A little more is needed to put back a multi-column range. I'm sure you'll manage. :D
set returningCelVals to {}
repeat with i from 1 to count of celVals
set end of returningCelVals to {item i of celVals}
end repeat
set value of range ("A1:A4") to returningCelVals
EDIT: I knew there is a better solution. Here it is:
set celVals to string value of range "A1:A4"
String value gives a two-dimensional array of values and error messages of the range. String value gives also e.g. cell's currency symbols, so it is perhaps not suitable to all situations.
I can't seem to locate a solution to a common scenario I face using Excel. My VBA ability is limited, so I'm not sure how to proceed with coding, but here is what I am trying to solve.
I have a spreadsheet listing rows that will frequently have additional rows mostly matching previous rows. For example, there may be two rows for the same customer, where the data is the same except that the second row has a different phone number. Everything else is the same, including a unique ID in column A. What I am looking to do is create code that will find a matching second (or additional) rows and blank any fields on the subsequent rows that match the previous, leaving any fields with different values alone.
This site won't let me insert a diagram showing what I'm talking about, but an example would be a spreadsheet with three columns- ID, Name, Phone. ID number 99 has two entries with the same ID and name, but different phone. I'd like to be able to blank the fields where the ID and name are duplicated and leave only the phone.
In this example, it's phone number, but it could be any column or combination of columns.
Is there a viable way to do this?
below has been tested:
Sub test()
For Each cell In Range("A3:C1000")
If cell.Value = cell.Offset(-1, 0).Value Then cell.ClearContents
Next
End Sub
just change Range to whichever Range you require, skipping first row(i skipped row 2) as it an anchor which is unique anyway.
P.S. this only works sequentially though so you need a sorted list
EDIT
first solution clearly was wrong, apologies, please try below, please note there is one caveat in it: if you have an entry in any particular column which repeats against some other entry which in fact is different - let say same phone number for a different customer, it will ALSO delete that entry.
it checks each entry against all previous entries in the same column, if it appeared previously, it will delete it.
Sub test()
Dim cell As Range
Dim c As Range
For Each cell In Range("A3:C1000")
On Error Resume Next
Set c = Range(Cells(2, cell.Column), Cells(cell.Row - 1, cell.Column)).Find(cell.Value)
On Error GoTo 0
If Not c Is Nothing Then
cell.ClearContents
End If
Next
End Sub
I admit I am completely new to Excel VBA. At the moment, I am in charge of generating a summary of data based of an automatically generated table of data spit out on a site. I already figured out how to scrape the data onto my Excel thankfully.
The scraped data is something of the following format:
TYPE | Number_Days_Logged | (a bunch of other important columns of data in row (6-7 items)|
What I need to do now is the following.
I need to do an if statement or comparison. There are two "types" under the type column. Let's say 0 and 1. I really only need type '1', so I need to filter out any 'type' 0's. Then I need to check the "number_days_logged". If this number is <= 1, I need to add it to a table with other entries with this condition. I then need to check "number_days_logged" for entries >= 85 and <100. These results will need to be put into a second table. Finally, I need to do the same this for values >= 100.
So in the end I need three different tables, the first with a green color formatting, then orange, and finally red. Each table need to be titled with the above information, though I really only need data from specific columns in each row. (each row is labeled, I just need a specific few columns)
This seems incredibly complicated to me, but I am willing to learn. If anyone can prod me in the correct direction, or make it simpler I would appreciate it. I can add any other details as required.
I think select statements are pretty clear and they tend to run a little faster too.
dim typeRange as range
set typeRange = range(cells(startRow,col),cells(stopRow,col))
dim entry as range
dim currentRow as integer
for each entry in typeRange
currentRow = entry.Row
if entry.value=1 then
select case cells(currentRow,'Number_Days_Logged's column').value
case is<=1
'copy and paste or transcribe the cells however you need them done.
case is<85
'do nothing
case is<100
'copy and paste or transcribe the cells however you need them done.
case is>=100
'copy and paste or transcribe the cells however you need them done.
end select
end if
next
You would first setup the tables with the colors you wanted, and (for this code) a named range for the data. I'd probably used named ranges for your tables also. Here's the skeleton of the VBA code.
Dim testrow As Range
For Each testrow in ActiveSheet.Range("Scraped Data")
If testrow.Cells(1) = 1 Then
If testrow.Cells(2) <= 1 Then
<add to 0-days table>
ElseIf testrow.Cells(2) >= 85 AND testrow.Cells(2) < 100 Then
<put in 2nd table>
ElseIf testrow.Cells(2) >= 100 Then
<put in third table>
End If
End If
Next testrow