Facing issues when joining rows of A column data into single cell at B column of 1st row - excel

I just want to bifurcate around 14900 rows of A column into 50 sets at each row in B column keeping # as delimiter. Example: 12345#5432333#3232#... till 50th row of A column. Like that I need to build 50 sets till row count of A column(14900) in each row of B column.
I developed code for the same using =TEXTJOIN("#",TRUE,A1:A14900) but this is failing, may be due to length issues in single cell. my plan is to break the output of this formula into 50 sets and place the same into each row of B column. if i use loop to make the formula dynamic then im worrying the length of cell again
-------- --------
12345566 12345566#333344444#98ZBRE322#1ZAZAZAQQ...till 50th row
333344444 next 50 sets
98ZBRE322 next 50 sets
1ZAZAZAQQ next 50 sets
Is there any best way to solve this issue?

Concatenate Ranges
Excel
In cell B1 use:
INDEX
=TEXTJOIN("#",TRUE,INDEX(A$1:A$14900,(ROW()-1)*298+1):INDEX(A$1:A$14900,ROW()*298))
OFFSET (Volatile)
=TEXTJOIN("#",TRUE,OFFSET(A$1:A$298,(ROW()-1)*298,0))
and copy down to cell B50.
VBA
Sub ConcatSets()
With ActiveSheet.Range("B1:B50")
' INDEX
.Formula = "=TEXTJOIN(""#"",TRUE,INDEX(A$1:A$14900,(ROW()-1)*298+1):INDEX(A$1:A$14900,ROW()*298))"
' OFFSET (Volatile)
'.Formula = "=TEXTJOIN(""#"",TRUE,OFFSET($A$1:$A$298,(ROW()-1)*298,0))"
' To keep only values use the following:
'.Value = .Value
End With
End Sub

Related

Transform hourly data in minute timestep data

I have an Excel file with hourly data, that is 8760 values on one year.
I need to have data at the minute-step.
I need to take the hourly value, and copy it to the 60 cells over and over again, until I have 525 600 values, being my minute timestep.
I tried a couple things, but haven't been able to do anything.
Update/Solution :
Sub test()
Worksheets("MySheet").Activate
Dim i As Double 'minutes increment
Dim j As Integer 'hourly increment
Dim k As Double
k = 0 'initialization of k
Dim Var1 As Single
Dim Var2 As Single
For j = 1 To 8760
Var1 = Cells(j, 8).Value 'Row "j"/from 1 to 8760, column "8"/H --> hourly values
Var2 = Cells(j, 7).Value 'Row "j"/from 1 to 60, column "7"/G --> minutes values
For i = 1 To 60
k = k + 1 'incrementation of k to be able to insert the values in the 60 cells (corresponding to 60 minutes)
Cells(k + 3, 10) = Var1 'insert those values in the 10th column (J)
Cells(k + 3, 9) = Var2 'insert those values in the 10th column (I)
Next i
Next j
End Sub
This can also be done without VBA, as given in answer, with the function =INDEX.
If the data are stored in a column (let's assume in column A) and you want a result also stored in a colum (let's assume in column B), a formula similar to this one might work:
=INDEX(A:A,QUOTIENT(ROW(B1)-1,60)+1)
Place it in cell B1 and drag it down.
If the data are stored in a row (let's assume in row 1) and you want a result also stored in a row (let's assume in row 2), a formula similar to this one might work:
=INDEX(1:1,QUOTIENT(COLUMN(A2)-1,60)+1)
Place it in cell A2 and drag it right.
As you can see the formula are basically the same. They are different just because one will work by being dragged down, the other by beign dragged right. If your list do not start from A1, the formulas can be easily adapted.
You could also write down a group of 60 cells the first one being 1, the following 59 being equal to the first one (by formula); then the 61st being would have been equal to the first plus 1 (always by formula), the following 59 equat to the 61st (again by formula). You can easily copy the second group as far as necessary. You then use a simple index formula linked to your new sequence of numbers to target the desired cell in the desired list.
Then again, you can also use VBA. It might be an overkill, though.
A data sample and/or more details might be needed if this answer isn't enouth.

Sum values in the column, if another column data are equal

I'm trying to analyze the data with >10K rows.
It contains 2 columns. 1st column has ID number. This number is repeating from row to row different times.
Columns 2 has just numbers, which I want to sum up if value in column 1 is the same.
For example: Image showing example attached.
First, what I did - is filtered from A/Z and trying with cycle find out qty of repeating items:
Private Sub CommandButton1_Click()
Dim row, B, i, col As Long
Dim H As Worksheet
Set H = Sheets("Sheet1")
H.Activate
row = H.Cells(Rows.Count, 1).End(xlUp).row
For B = 4 To row
i = 1
j = H.Cells(B, 2).Value
If H.Cells(B, 1).Value = H.Cells(B + 1, 1).Value Then
i = i + 1
.....
Result of sum I want to place in the last row where same IDs are matching. And after all, delete those not required ones.
Appreciate in advance any help on this.
If you want to delete rows after summing then VBA is best. Otherwise you can achieve out using excel formulas only. First you need to extract unique value from first column. Then you need to sum values based on unique values you extracted. So if you have Office365 then use UNIQUE() function to extract unique values like below.
=UNIQUE(A1:A14)
Then use SUMIF() to sum for these unique values.
=SUMIF($A$2:$A$14,D2,$B$2:$B$14)
You can just use a Pivot Table.
Since you will be updating/refreshing the data:
Select a cell in your data table and Insert/Table
Then, depending on your Excel version: Summarize with Pivot Table (or similar)
Note that there is no need to sort the data.
Then you merely drag
ID to the Rows area
Value to the Values area
If your values are numeric, it should default to Sum of Values
Rename / Format / decide on totals and subtotals, etc.
To refresh, the data after changing it, you merely need to select Data/Refresh, or you can create a command button to do the same.

Highlight exceeding limit in VBA

line customer product OrderQty TotalQty
1 A 11111 5 10
2 B 11111 5 10
3 c 11111 5 10
4 A 22222 5 20
5 B 22222 5 20
6 C 22222 5 20
I have a table as shown above.
I want to to highlight the lines when OrderQty is bigger than TotalQty for a product.
OrderQty represents the number of units requested for in that order, TotalQty represents total units available to fulfil all orders.
In this example, I want to highlight lines 1,2,3 as product 11111 OrderQty 5+5+5=15 is bigger than TotalQty 10.
Is there a way to automate this in VBA? I suspect using Sumifs but I can't wrap my head around..
Thanks in advance!
You don't need VBA for this. Assuming your table above starts on row 1 with Line in column A and TotalQty in column E; put a unique list of Product in column F and in cell G2 put the formula:
=IF(SUMIF(C:C,F2,D:D)>VLOOKUP(F2,C:E,3,FALSE), "Over", "Equal or under")
The SUMIF sums OrderQty for each Product, the VLOOKUP returns TotalQty for the first instance of each Product found in the table. You can then use conditional formatting to highlight rows if required.
If you did go the VBA route, I'd probably put the table into an array, create a dictionary of Product with a value for OrderQty, and either loop on the array and sum values, or loop on the dictionary keys and call the sumif worksheet function.
Maybe something like this ?
Sub test()
Range("A:E").Interior.Pattern = xlNone
Range("C1:C7").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("AA1"), Unique:=True
Set Rng = Range("AA2", Range("AA100000").End(xlUp))
For Each Prod In Rng
Set c = Range("C:C").Find(Prod.Value, lookat:=xlWhole)
Tot = c.Offset(0, 2).Value
Ord = Application.SumIf(Range("C:C"), Prod.Value, Range("D:D"))
If Ord > Tot Then
For Each cell In Range("C2", Range("C2").End(xlDown))
If cell.Value = Prod.Value Then
Range(cell.Offset(0, -2), cell.Offset(0, 2)).Interior.Color = 65535
End If
Next cell
End If
Next Prod
Range("AA:AA").ClearContents
End Sub
Or if you choose without VBA, use Conditional Formatting.
Select the range you want to be highlighted
Click Conditional Formatting ---> New Rule
Choose "Use a formula to determine which cells to format"
Type =SUMIF($C:$C,$C2,$D:$D)>VLOOKUP($C2,$C:$E,3,FALSE) in the formula box
Click Format button, then do the formatting as you want
Click OK, Click OK.
[Good day Kyle,
Is this what you are trying to do. This is only simple solution but can help you.
I used a helping column for your criteria you mentioned. I used sumifs. You can modify it to your style and needs. I used conditional formatting to highlight cells.]1
First, streamline your table, divide into two tables:
line, customer, product, OrderQty in one table.
product, TotalQty other table.
Assuming {product,TotalQty} in 'Sheet 2', and the other table in 'Sheet 1', then add a column in second table (C column in sheet 2) 'OrderQty>TotalQty' and insert formula in the cell below it, as follows:
=IF(SUMIF(Sheet1!$C:$C,$A2,Sheet1!$D:$D)>$B2,"Yes","No")
Drag or copy-paste the formula to remaining product rows.
Screenshots:

Excel: Merge two columns into one column with alternating values

how can I merge two columns of data into one like the following:
Col1 Col2 Col3
========================
A 1 A
B 2 1
C 3 B
2
C
3
You can use the following formula in column D as per my example. Keep in mind to increase the $A$1:$B$6 range according to your data.
=INDEX($A$1:$B$6,INT((ROWS(D$2:D2)-1)/2)+1,MOD(ROWS(D$2:D2)-1,2)+1)
Result:
Thank you to #Koby Douek for the answer. Just an addition--if you are using Open Office Calc, you replace the commas with semi-colons.
=INDEX($A$1:$B$6;INT((ROWS(D$2:D2)-1)/2)+1;MOD(ROWS(D$2:D2)-1;2)+1)
Expanding #koby Douek's answer to more columns and explaining some of the terms
Original Code for 2 columns to 1 alternating
=INDEX($A$1:$B$6,INT((ROWS(D$2:D2)-1)/2)+1,MOD(ROWS(D$2:D2)-1,2)+1)
$A$1:$B$6 Defines the columns and rows to source the final set of data from, the $s are only present to keep the formula from changing the columns and rows selects if it is copied and pasted or dragged.
To extend to work on any values you dump into the columns instead of having to expand the range every time it should be amended to $A:$B or A:B so you can easily copy it to other sets of columns and create new merges, but it will also give the 1st value in every column as one of the alternating values so if you instead have headers you would be able to do this by instead using a large number so $A$1:$B$99999 or A$1:B$99999 if you want to past and move the columns ymmv which is better by situation.
lets assume you are fine including the values in the 1st row
This changes the formula to
=INDEX($A:$B,INT((ROWS(D$2:D2)-1)/2)+1,MOD(ROWS(D$2:D2)-1,2)+1)
Now on to D$2:D2
This is the row that is being used to calculate the difference between the current row the formula is in (D2) and the reference row (D$2) The important thing to make sure you do is to set the reference row number to the 1st row you will be putting values in, so if your 1st row is a header in the sort column you will use the 2nd row as the reference, if your values in the combined column D begin on the 3rd row then the reference row would be D$3
Since I like the more general form where the 1st row isn't a header row I'll use D$1:D1 but you could still mix source rows without headers into a combined row with a header of as many rows as you like just by incrementing that reference row number to be the 1st row where your values should begin.
This changes the formula to
=INDEX($A:$B,INT((ROWS(D$1:D1)-1)/2)+1,MOD(ROWS(D$1:D1)-1,2)+1)
Now INT((ROWS(D$1:D1)-1)/2)+1 and MOD(ROWS(D$1:D1)-1,2)+1
INT returns an integer value so any decimal places are dropped, it essentially functions like rounding down to the nearest whole number
MOD functions by returning the remainder of a division, it's result will be a whole number between 0 and n-1 where n is the number we are dividing by. (eg: 0/3=0; 1/3=1; 2/3=2; 3/3=0; 4/3=1 ... etc)
So -1)/2)+1 and -1,2)+1
the first value is again the difference between the current row and the reference row. but D$1:D1 is going to be the count of the rows, which is 1 so we have to correct for the rows count starting at 1 instead of 0 which would throw off our calculations, so both are using the -1 to reduce the count of the rows by 1
in the case of /2 and ,2 both are because we are dividing by 2 in the first statement it's a normal division by 2 /2 in the modulus statement it's an argument of the Mod function so ,2
finally we need to add 1 using +1 to correct for the index's need to have a value series which begins at 1.
INT((ROWS(D$2:D2)-1)/2)+1 is finding the row number to select the value from.
MOD(ROWS(D$1:D1)-1,2)+1 is finding the column number to select the value from
Thus we can change /2 and ,2 to /3 and ,3 to do this with 3 columns
This yields:
=INDEX($A:$B,INT((ROWS(D$1:D1)-1)/3)+1,MOD(ROWS(D$1:D1)-1,3)+1)
So maybe that's the confusing way to look at it but it's closer to how my mind works on it. Here is an alternative view:
=INDEX([RANGE],[ROW_#],[COLUMN_#]) returns the value from a range of rows and columns
Using the example:
=INDEX($A:$B,INT((ROWS(D$1:D1)-1)/3)+1,MOD(ROWS(D$1:D1)-1,3)+1)
[RANGE] = $A:$B this is the range of source columns.
[ROW_#] = INT((ROWS(D$1:D1)-1)/3)+1
INT([VALUE_A])+1 returns an integer value so any decimal places are dropped. Then adds one to it. we add one to the value because the result of the next steps will be 1 less than the value we need.
[Value_A] = (ROWS(D$1:D1)-1)/3
ROWS(D$1:D1) returns the number of rows in the Range to the current row in the results column, we use D$1 to designate the row number where the values in the results column begin. D1 is the current row in the results column giving us a range from the source row, allowing us to count the rows. we have to subtract 1 from this value using -1 to get the difference between the source and current. This is then divided by /3 because we have three columns we want to look through in this example so we only change rows when the result is divisible by 3. the INT drops any decimal places as mentioned so it only increments when cleanly divisible by 3.
[COLUMN_#] = MOD(ROWS(D$1:D1)-1,3)+1
MOD([VALUE],[Divisor])+1 returns the remainder of the value when divided by the divisor.
Using the example:
MOD(ROWS(D$1:D1)-1,3)+1
In this case we still divide by 3 but it's an argument to the MOD function, we still need to count the number of rows and subtract 1 before dividing it, this will return a 0, 1, or 2 for the column, but as above we are shifted backwards by 1 as the column numbers begin with the number 1, so as before we must add 1
And here we add column A and D
two different formulas depending on if you add the formula to an odd row or an even row.
https://1drv.ms/x/s!AncAhUkdErOkguUaToQkVkl5Qw-l_g?e=5d9gVM
Odd Start row
=INDEX($A$2:$D$9;ROUND(ROW(A1)/2;0);IF(MOD(ROW()-ROW($A$2);2)=1;4;1))
Even Start row
=INDEX($A$2:$D$9;ROUND(ROW(A1)/2;0);IF(MOD(ROW()-ROW($A$1);2)=1;4;1))
What is A1 in the picture is the cell directly above your first data cell.
If you want to place it on a different sheet you just add the sheet name:
=INDEX(MySheet!$A$2:$D$9;ROUND(ROW(MySheet!A1)/2;0);IF(MOD(ROW()-ROW(MySheet!$A$2);2)=1;4;1))
=INDEX(MySheet!$A$2:$D$9;ROUND(ROW(MySheet!A1)/2;0);IF(MOD(ROW()-ROW(MySheet!$A$1);2)=1;4;1))

Excel: finding a given number criteria meeting cells from right to left

I need to find the average of 8 last (rightmost, from right to left) numeric cell values in a row that meet simple criteria of >= 0, ie. zero or positive numbers from rows that contain a mix of zeroes, and negative and positive values. In other words, I need to find the 8th cell reference from all cells containing 0 or higher counting from the end of the row backwards.
Example row:
1.6425 0.6233 5.2899 4.4372 2.0356 3.9796 1.5306 3.8344 0 -1 -1 3.8294 -1 3.0957 0 3.7572 -1
Expected result:
2.50
(3.7572 + 0 + 3.0957 + 3.8294 + 0 + 3.8344 + 1.5306 + 3.9796) / 8
I solved this cleanly using AVERAGEIFS and adding only one supplementary row A2:Q2 to mark just the 8 cells required. This extra row counts backwards from the end of the row, iterating by one from the previous count (next cell to the right) only if the cell above in row 1 is not less than 0, with the formula =IF(A1<0,B2,B2+1) copied throughout row A2:Q2. This then acts as criteria2 for the main formula i.e. use the first 8 cells from the right with a value >=0.
Then it's a simple =AVERAGEIFS(A1:Q1, A1:Q1, ">=0", A2:Q2, "<9") in cell C4 to get the result. C5 is a simple manual test against the calculated result.
Here's the Excel file: https://dl.dropbox.com/u/4974539/averageifs_tweak.xlsx - and a screen shot:
I solved your problem but with plenty of auxiliary columns. In the following I assume you have your data in columns A to Q, starting in row 2
On the first row, put letters A to J in columns T to AC
On the first data row
2.1 Put the forumula =ROW() in column S
2.2 Put array formula (press Shift + Ctrl + Enter when entering it) =SUM(IF(INDIRECT(T$1 & $S2 & ":Q" & $S2,TRUE)>=0,1,0)) to column T and copy it right all the way to column AC
2.3 Enter array formula =INDEX($T$1:$AC$1,MATCH(8,T2:AC2,0)) in column AD
2.4 Finally, put array formula =SUM(IF(INDIRECT(AD2 & S2 & ":Q" & S2) >= 0, INDIRECT(AD2 & S2 & ":Q" & S2), 0))/8 to column AE, this is the result you want
You can copy the row with formulas down to every row with data
This is how it looks in my Excel:
What it does:
in column S is the current row -- we need it for the INDIRECT function, because ROW() does not work in INDIRECT in array functions.
in columns T - AC we count the number of columns in the right side of the current row of data that are positive or zero, starting in different columns -- their letters are on the first row. The rightmost column where we can start is J, otherwise there would not be
8 values.
in column AD we match number 8 and from the first row we get the column where we have to start the range for averaging
finally, in column AE we use INDIRECT to create the reference to the range we want, sum all the numbers that are >= 0 and divide by 8

Resources