I probably just am just going a little batty at the moment. Surely there's something real simple I'm missing.
If anyone has an idea how to rearrange my logic or hit me up side the head with a brick, I'll take any "help".
We have a CSV output file that I need to keep a portion of the data and sort of pivot it (only it doesn't really work for a pivot table, and thus why I'm writing VBA).
The data I need to use looks like this:
And then LOTS more of it. So there are MANY Elements per Label, and typical 1 to 4 Data points (4th column or column D for easier reference) for each Element. There could be a flag for any given Label-Element point that shows what's wrong with the Data column.
What I've already done (this much works):
I've deduped the Label column in a new sheet so we can have one row per Label.
I've deduped the Element column and put it across the top row (B1 to the right, however many columns needed) for Column headers
That part works great.
Where I've goofed in logic somehow is telling Excel:
1. Whenever there's a Flag in column C from original Sheet, FIRST append that to a variable to concatenate multiple flags with their Data values.
Example: if there are 2 data values for one Element that have a flag, then it could be a string of 000.23 Y, 000.54 Z
2. Once I've found the flags for a particular Label,Element combo, whether that be 1, 2, 3, or 4, paste the stored variable value into the proper "grid" location on the new worksheet.
3. Move on to the next Label/Element pair.
My logic finds the flags.
However, my logic goes wonky on finding where to plug in the flags. For some reason I've got it plugging in flag values where there should be just blank/empty cells (if no flags, we're leaving the new cells blank).
My messy code:
I'm still working on this. If anyone has any suggestions whatsoever, I'm all ears. Thanks in advance.
And I can try to fill in more blanks if necessary as well. Hopefully my explanation explained what I"m trying to do.
One option in the back of my mind is using MSQuery, but I am not sure that'll really handle this setup since there are multiple records...
"But thanks be to God, which giveth us the victory through our Lord Jesus Christ." 1 Corinthians 15:57
If anyone has an idea how to rearrange my logic or hit me up side the head with a brick, I'll take any "help".
We have a CSV output file that I need to keep a portion of the data and sort of pivot it (only it doesn't really work for a pivot table, and thus why I'm writing VBA).
The data I need to use looks like this:
Code:
Label Element Flags Data
Blank Ag 328.068 [Empty] 0
Blank Al 396.152 [Empty] 0
Blank As 188.980 [Empty] 0
Blank As 193.696 [Empty] 0
Blank B 208.956 [Empty] 0
Blank B 249.678 [Empty] 0
Blank Ba 233.527 [Empty] 0
Blank Ba 455.403 [Empty] 0
Blank Be 313.042 [Empty] 0
Blank Ca 315.887 [Empty] 0
Blank Ca 393.366 [Empty] 0
Blank Ca 422.673 [Empty] 0
20 ppm Y 224.303 [Empty] 0.9451
20 ppm Y 371.029 [Empty] 0.9357
20 ppm Y 371.029 [Empty] 0.935
20 ppm Zn 206.200 [Empty] 20
20 ppm Zn 213.857 [Empty] --
20 ppm Zn 334.502 [Empty] 20
PBlnk Ag 328.068 Y! 0.0615
PBlnk Al 396.152 ! 0.0006
PBlnk As 188.980 ! 0.0054
PBlnk As 193.696 ! 0.0041
PBlnk B 208.956 !u 0.0009
PBlnk B 249.678 !u -0.0052
PBlnk Ba 233.527 !u -0.0001
PBlnk Ba 455.403 !u -0.0001
PBlnk Be 313.042 !u 0
PBlnk Ca 315.887 Y! 0.0576
And then LOTS more of it. So there are MANY Elements per Label, and typical 1 to 4 Data points (4th column or column D for easier reference) for each Element. There could be a flag for any given Label-Element point that shows what's wrong with the Data column.
What I've already done (this much works):
I've deduped the Label column in a new sheet so we can have one row per Label.
I've deduped the Element column and put it across the top row (B1 to the right, however many columns needed) for Column headers
That part works great.
Where I've goofed in logic somehow is telling Excel:
1. Whenever there's a Flag in column C from original Sheet, FIRST append that to a variable to concatenate multiple flags with their Data values.
Example: if there are 2 data values for one Element that have a flag, then it could be a string of 000.23 Y, 000.54 Z
2. Once I've found the flags for a particular Label,Element combo, whether that be 1, 2, 3, or 4, paste the stored variable value into the proper "grid" location on the new worksheet.
3. Move on to the next Label/Element pair.
My logic finds the flags.
However, my logic goes wonky on finding where to plug in the flags. For some reason I've got it plugging in flag values where there should be just blank/empty cells (if no flags, we're leaving the new cells blank).
My messy code:
Code:
Sub PivotMyData()
Dim wb As Workbook
Dim ws As Worksheet
Dim wsNew As Worksheet
Dim wsClean As Worksheet [green]'to just clean up the Elements[/green]
Dim lRowO As Long [green]'Origin sheet Row[/green]
Dim lRowN As Long [green]'New sheet row[/green]
Dim iColN As Integer [green]'New sheet col[/green]
Dim strLabel As String [green]'Label value from sheet[/green]
Dim strElement As String [green]'Element (to go across column headers)[/green]
Dim strResult As String [green]'Result (Unadjusted Data + " " + flag)
'strResult should start as null string then add to it as find flags per element per label[/green]
Dim strCurrRes As String [green]' in case need to capture each one separately...[/green]
Dim rLastElement As Range [green]'last Element range looked at.[/green]
Dim rLastFlag As Range [green]'last flag found[/green]
Dim lFindNextRow As Long
Dim rAnchor As Range [green]'anchor will be cell A1 in new worksheet for ease of reference.[/green]
Set wb = ActiveWorkbook
Set ws = wb.ActiveSheet
[green]'delete the first two rows from CSV as they just get in way[/green]
ws.Rows(1).EntireRow.Delete
ws.Rows(1).EntireRow.Delete
[green]'Save the file as an Excel file[/green]
ActiveWorkbook.SaveAs Filename:= _
Replace(wb.FullName, ".csv", ".xlsx"), FileFormat:= _
xlOpenXMLWorkbook, CreateBackup:=False
[green]'Delete unnecessary columns[/green]
ws.Columns("H:AH").EntireColumn.Delete
ws.Columns("E").EntireColumn.Delete
ws.Columns("B:C").EntireColumn.Delete
[green]'Sort the data to ensure things are definitely lined up properly - we may be able to prove this is not needed later, but want to add for now to be safe.[/green]
ws.Range("A1").CurrentRegion.Select
ws.Sort.SortFields.Clear
ws.Sort.SortFields.Add2 Key:= _
Range("A2:A14911"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
ws.Sort.SortFields.Add2 Key:= _
Range("B2:B14911"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
ws.Sort.SortFields.Add2 Key:= _
Range("D2:D14911"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption _
:=xlSortNormal
With ws.Sort
.SetRange Range("A1:D14911")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
[green]' Add new worksheet for viewing the data differently - in the QC layout[/green]
Set wsNew = wb.Worksheets.Add
Set wsClean = wb.Worksheets.Add 'to clean up labels
[green]' Rename the new sheets[/green]
wsNew.Name = "ICP QC"
wsClean.Name = "CleanUP"
[green]'******************* Main parts of code for getting data into workable layout *********************
'****************************
' ----------- 01 Grab Elements to use as a COLUMN headers.
'****************************
' copy the Element data to the new worksheet[/green]
ws.Range("B2:B" & ws.Range("B999999").End(xlUp).Row).Copy wsNew.Range("A2")
' remove duplicates
wsNew.UsedRange.RemoveDuplicates 1, xlNo
[green]' Remove blank cells (we don't want blank column headers if any blank values exist[/green]
On Error Resume Next
ws.UsedRange.SpecialCells(xlCellTypeBlanks).Delete Shift:=xlShiftUp
On Error GoTo 0
[green] ' copy the range to now be the column headers[/green]
wsNew.Range("A2:A" & ws.Range("A999999").End(xlUp).Row).Copy
[green] ' transpose to the header row starting with column B[/green]
wsNew.Range("B1").PasteSpecial Transpose:=True
[green] ' delete the original pasted data from Column A[/green]
wsNew.Range("A2:A" & wsNew.Range("A999999").End(xlUp).Row).Delete xlShiftUp
[green]'****************************
' ----------- 02 Grab the Labels to be used as ROW headers.
'****************************
' copy the Label data to the new worksheet[/green]
ws.Range("A2:A" & ws.Range("A999999").End(xlUp).Row).Copy wsClean.Range("A2")
[green] ' remove duplicates[/green]
wsClean.UsedRange.RemoveDuplicates 1, xlNo
[green]' Copy the cleaned data to wsNew for QC data (copy to A2 for column headers (Labels)[/green]
wsClean.Range("A2:A" & wsClean.Range("A999999").End(xlUp).Row).Copy wsNew.Range("A2")
[green] ' THERE IS NO WAY THERE WOULD BE BLANKS IN LABELS So can skip checking for blanks
' strLabel = Label value from sheet
' strElement = Element (to go across column headers)
' strResult = Result (Unadjusted Data + " " + flag)
' strCurrRes = in case need to capture each one separately...
[highlight #FCE94F]' *************************************************************************************************************************
' *************************************************************************************************************************
' *************************************************************************************************************************
' *************************************************************************************************************************
' ***** BELOW IS SECTION WHERE THE LOGIC MESS CURRENTLY EXISTS THAT I NEED TO FIX ****************************************
' *************************************************************************************************************************
' *************************************************************************************************************************
' *************************************************************************************************************************[/highlight]
'****************************
' ----------- 03 POPULATE THE flag and Result where it fits
' NOW THAT I HAVE COLUMN AND ROW HEADERS, POPULATE THE flag and Result where it fits
' for that need to loop through original data (ws) and fill where fits on new data (wsNew)
' To do this right, will build each value now in the loop that was goign to be original logic by finding all possible values for each Row and each column in new data
'****************************
[/green]
Set rAnchor = wsNew.Range("A1") 'for easier reference
lRowO = 1 [green]'start from the header row b/c always searching for the next found row of data[/green]
Do Until lRowO = ws.Range("C999999").End(xlUp).Row
[green]' this section gets us to each flag so we don't have to actually look at every single row of data[/green]
lFindNextRow = ws.Range("C3").EntireColumn.Find(What:="?*", After:=Range("C" & lRowO), LookIn:=xlValues).Row
If lFindNextRow <= 1 Then lFindNextRow = 0
lRowO = lFindNextRow
[green] ' set the initial value[/green]
If strResult = vbNullString Then strResult = ws.Range("D" & lRowO).Value & " " & ws.Range("C" & lRowO).Value
If strLabel = vbNullString Then strLabel = ws.Range("A" & lRowO).Value
If strElement = vbNullString Then strElement = ws.Range("B" & lRowO).Value
[green]' If the Label for that element is same as the current Label working with (strLabel), then add the current result and flag to string variable[/green]
If ws.Range("B" & lRowO).Value = strElement And ws.Range("A" & lRowO).Value = strLabel Then
[green] ' If both are the same as what already dealing with, then append the Flag to the strResult variable[/green]
If strResult = ws.Range("D" & lRowO).Value & " " & ws.Range("C" & lRowO).Value Then
Else
strResult = strResult & ", " & ws.Range("D" & lRowO).Value & " " & ws.Range("C" & lRowO).Value
End If
Else
[green] ' If the ELEMENT or the LABEL changes, then I know it's a different record we want to work with, regardless.
' When different, this is when need to find where to plug the values
' find the column and row where to paste the strResult value
'Debug.Print "rAnchor = " & rAnchor.Address
'Debug.Print "strLabel = " & strLabel
'Debug.Print "strElment = " & strElement
[/green]
wsNew.Activate
rAnchor.Select
lRowN = Cells.Find(What:=strLabel, After:=rAnchor, LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False).Row
iColN = Cells.Find(What:=strElement, After:=rAnchor, LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False).Column
wsNew.Cells(lRowN, iColN).Value = strResult
[green] ' clear out the result[/green]
strResult = vbNullString
[green] ' repopulate everything according to what the current row in original worksheet is[/green]
strLabel = ws.Range("A" & lRowO).Value
strElement = ws.Range("B" & lRowO).Value
strResult = ws.Range("D" & lRowO).Value & " " & ws.Range("C" & lRowO).Value
End If
[green]' **** End non-empty flag loop[/green]
Loop [green]'Do Until lRowO = ws.Range("C999999").End(xlUp).Row[/green]
[highlight #FCE94F]' *************************************************************************************************************************
' *************************************************************************************************************************
' *************************************************************************************************************************
' *************************************************************************************************************************
' ***** [b]ABOVE[/b] IS SECTION WHERE THE LOGIC MESS CURRENTLY EXISTS THAT I NEED TO FIX ****************************************
' *************************************************************************************************************************
' *************************************************************************************************************************
' *************************************************************************************************************************[/highlight]
wb.Save
On Error Resume Next
Set rAnchor = Nothing
Set ws = Nothing
Set wsNew = Nothing
Set wb = Nothing
End Sub
I'm still working on this. If anyone has any suggestions whatsoever, I'm all ears. Thanks in advance.
And I can try to fill in more blanks if necessary as well. Hopefully my explanation explained what I"m trying to do.
One option in the back of my mind is using MSQuery, but I am not sure that'll really handle this setup since there are multiple records...
"But thanks be to God, which giveth us the victory through our Lord Jesus Christ." 1 Corinthians 15:57