VBA: avoid empty cells when creating array from pivottable - arrays

I'm trying to create an array based on a pivot table with multiple empty cells, however instead of referring to previous value, the array keeps all the empty cells:
For AllCostTypeRowCounter = 1 To SiteRowCount
AllCostTypeArrayCounter = AllCostTypeArrayCounter + 1
ReDim Preserve AllCostTypeArray(2, AllCostTypeArrayCounter)
If Not CountryRange(AllCostTypeRowCounter, 1) Is Nothing Then
AllCostTypeArray(1, AllCostTypeArrayCounter) = CountryRange(AllCostTypeRowCounter, 1)
Else
AllCostTypeArray(1, AllCostTypeArrayCounter) = AllCostTypeArray(1, AllCostTypeArrayCounter - 1)
End If
AllCostTypeArray(2, AllCostTypeArrayCounter) = SiteRange(AllCostTypeRowCounter, 1).Value
Next AllCostTypeRowCounter

Nvm I solved the question by changing the following code:
If Not CountryRange(AllCostTypeRowCounter, 1) Is Nothing Then
to:
If CountryRange(AllCostTypeRowCounter, 1) <> "" Then
Can anyone tell me why this change works. The above seems the same to me. Also how do I close my own post?

Related

calculating null or empty value in Access report returns #Type! error

i have database which has Column 'Name' of the employee with "Surname, Name" like ' Gambel, Peter'.
I want to replace this name in report like ' Peter. G'. I have created a Vba function which converts the Name like as shown above, but if the field value is empty than it always return me '#Type!'. I have tried a lot but still i am unable to resolve this error.
Public Function name_change(Name_pass As String) As String
If (IsNull(Name_pass) Or Name_pass = "") Then
name_change = "-"
Else
Dim Name_split() As String
Name_split = split(Name_pass, ",")
Name_split(0) = Left$(Name_split(0), 1)
name_change = Name_split(1) & "." & Name_split(0)
End If
End Function
If not comma is present, UBound of of Name_split is 0 and Name_split(1) will fail.
As Gustav points out you are only checking for an empty string, but not for one that has no comma. You need something like this:
If Nz(Name_pass) LIKE "*,*" Then
Dim Name_split() As String
Name_split = split(Name_pass, ",")
Name_split(0) = Left$(Name_split(0), 1)
name_change = Name_split(1) & "." & Name_split(0)
Elseif Trim(Nz(Name_pass)) = "" then
name_change = "-"
Else
[Deal with names that have content but not comma]
End if
Finally I find the answer.
In control source before passing the value to function we have to check the value is Null or not with NZ function.
=name_change(Nz([Name],"-"))
Thanks guys for your input.

Calculate Sum and Insert as Row

Using SSIS I am bringing in raw text files that contain this in the output:
I use this data later to report on. The Key columns get pivoted. However, I don't want to show all those columns individually, I only want to show the total.
To accomplish this my idea was calculate the Sum on insert using a trigger, and then insert the sum as a new row into the data.
The output would look something like:
Is what I'm trying to do possible? Is there a better way to do this dynamically on pivot? To be clear I'm not just pivoting these rows for a report, there are other ones that don't need the sum calculated.
Using derived column and Script Component
You can achieve this by following these steps:
Add a derived column (name: intValue) with the following expression:
(DT_I4)(RIGHT([Value],2) == "GB" ? SUBSTRING([Value],1,FINDSTRING( [Value], " ", 1)) : "0")
So if the value ends with GB then the number is taken else the result is 0.
After that add a script component, in the Input and Output Properties, click on the Output and set the SynchronousInput property to None
Add 2 Output Columns outKey , outValue
In the Script Editor write the following script (VB.NET)
Private SumValues As Integer = 0
Public Overrides Sub PostExecute()
MyBase.PostExecute()
Output0Buffer.AddRow()
Output0Buffer.outKey = ""
Output0Buffer.outValue = SumValues.ToString & " GB"
End Sub
Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
Output0Buffer.AddRow()
Output0Buffer.outKey = Row.Key
Output0Buffer.outValue = Row.Value
SumValues += Row.intValue
End Sub
I am going to show you a way but I don't recommend adding total to the end of the detail data. If you are going to report on it show it as a total.
After source add a data transformation:
C#
Add two columns to your data flow: Size int and type string
Select Value as readonly
Here is the code:
string[] splits = Row.value.ToString().Split(' '); //Make sure single quote for char
int goodValue;
if(Int32.TryParse(splits[0], out goodValue))
{
Row.Size = goodValue;
Row.Type = "GB";
}
else
{
Row.Size = 0;
Row.Type="None";
}
Now you have the data with the proper data types to do arithmatic in your table.
If you really want the data in your format. Add a multicast and an aggregate and SUM(Size) and then merge back into your original flow.
I was able to solve my problem in another way using a trigger.
I used this code:
INSERT INTO [Table] (
[Filename]
, [Type]
, [DeviceSN]
, [Property]
, [Value]
)
SELECT ms.[Filename],
ms.[Type],
ms.[DeviceSN],
'Memory Device.Total' AS [Key],
CAST(SUM(CAST(left(ms.[Value], 2) as INT)) AS VARCHAR) + ' GB' as 'Value'
FROM [Table] ms
JOIN inserted i ON i.Row# = ms.Row#
WHERE ms.[Value] like '%GB'
GROUP BY ms.[filename],
ms.[type],
ms.[devicesn]

Gembox get count of all rows (including blank) of specfic column

I am trying to get count of last used row for a specific column, but was only able to get count of max rows occupied. Test data is shown in attached snap. Please help. Snap Attached Here
SpreadsheetInfo.SetLicense("FREE-LIMITED-KEY");
ExcelFile ef = ExcelFile.Load("test.xlsx");
CellRange rcount = ef.Worksheets[0].Columns[1].Cells;
Console.WriteLine(ef.Worksheets[0].Rows.Count);
ef.Save("test.xlsx");
Console.ReadKey();
Cells are internally allocated in rows, not in columns. In other words, you could get the last used column for each row with ExcelRow.AllocatedCells.Count.
For getting the last used row in a specific column you can use something like the following:
ExcelFile ef = ExcelFile.Load("test.xlsx");
ExcelWorksheet ws = ef.Worksheets[0];
ExcelColumn column = ws.Columns[1];
int rowIndex = ws.Rows.Count - 1;
while (rowIndex >= 0 && column.Cells[rowIndex].ValueType == CellValueType.Null)
--rowIndex;
Console.WriteLine(rowIndex);
I hope this helps.

How to filter data in VBA?

I am working on a AddIn which is based on VBA. I import data from XML file. I want to apply filter on that data. I don't know how can I store and organize data.
XML File:
<?xml version="1.0"?>
<TestClass>
<TestObject>
<Site>Facebook</Site>
<Name>ABC</Name>
<URL>https://www.facebook.com/ABC/</URL>
</TestObject>
<TestObject>
<Site>Facebook</Site>
<Name>XYZ</Name>
<URL>https://www.facebook.com/XYZ/</URL>
</TestObject>
<TestObject>
<Site>Twitter</Site>
<Name>ABC</Name>
<URL>https://www.twitter.com/ABC/</URL>
</TestObject>
<TestObject>
<Site>Facebook</Site>
<Name>XYZ</Name>
<URL>https://www.twitter.com/XYZ/</URL>
</TestObject>
</TestClass>
Here is my code.
Set oXMLFile = CreateObject("Microsoft.XMLDOM")
XMLFileName = "C:\Users\abc\Desktop\TestFiles\TestData.xml"
oXMLFile.Load (XMLFileName)
Set Sites = oXMLFile.SelectNodes("TestClass/TestObject/Site/text()")
Set Names = oXMLFile.SelectNodes("TestClass/TestObject/Name/text()")
Set URLs = oXMLFile.SelectNodes("TestClass/TestObject/URL/text()")
Public SiteArray(100) As String
Public NameArray(100) As String
Public URLArray(100) As String
For i = 0 To (Sites.Length - 1)
SiteArray(i) = Sites(i).NodeValue
NameArray(i) = Names(i).NodeValue
URLArray(i) = URLs(i).NodeValue
Next
Now I don't know how to get list of Name where Site is Facebook. I also want to get list of URL of Twitter.
Can anybody please suggest me mechanism for filtering in above case?
Based on what you've said you want, I've amended your code and added comments to explain what I'm doing:
Set oXMLFile = CreateObject("Microsoft.XMLDOM")
XMLFileName = "C:\Users\abc\Desktop\TestFiles\TestData.xml"
oXMLFile.Load (XMLFileName)
Set Sites = oXMLFile.SelectNodes("TestClass/TestObject/Site/text()")
Set Names = oXMLFile.SelectNodes("TestClass/TestObject/Name/text()")
Set URLs = oXMLFile.SelectNodes("TestClass/TestObject/URL/text()")
Public myArray() As String ' declare array as dynamic so we can amend its size
ReDim myArray(6,0) ' reset it to be 2 dimensional
For i = 0 To (Sites.Length - 1)
myArray(0,i) = Sites(i).NodeValue ' Column 1 of the array contains Sites
myArray(1,i) = Names(i).NodeValue ' Column 2 of the array contains Names
myArray(2,i) = URLs(i).NodeValue ' Column 3 of the array contains URLs
myArray(3,i) = URLs(i).NodeValue ' Column 4 of the array contains URLs
myArray(4,i) = URLs(i).NodeValue ' Column 5 of the array contains URLs
myArray(5,i) = URLs(i).NodeValue ' Column 6 of the array contains URLs
myArray(6,i) = URLs(i).NodeValue ' Column 7 of the array contains URLs
ReDim Preserve myArray(6, UBound(myArray,2)+1) ' increase the size of the array dynamically to include an extra "row" of data
Next
' Now you can loop through and search for anything you want, like so:
For i = 0 to UBound(myArray, 2) ' loop through all the "rows" of the array
If Instr(LCase(myArray(0,i)), "facebook") > 0 Then ' If the site contains facebook
myName = myArray(1, i) ' returns the associated name for the Site
myURL = myArray(2, i) ' returns the associated URL for the Site
' Do whatever you need with this info then let the loop continue through the rest of the rows or use an Exit For statement to break the loop
End If
Next

VB.Net : Create a Recordset with manual inputs and GetRows() methods failing

First time writing on a forum but this one really left me no choice and it seems that nobody had the same problem as I have... not a good sign...
I have a project to use the COM Server of a software we use internally and need to use one of their built-in function which requires a recordset as an input and return another recordset with the results (important because I need to stick with the recordset).
Here's breifly what I tried. I create a recordset from scratch and fill it with some hardcoded data just for testing purposes. Once my recordset is filled, I want to look at the data just to be sure everything works well, but I'll have to do the same eventually with my results.
The problem I get is it seems that the GetRows() method return only 1 row every time depending on the last row I moved to. But once it's called, I cannot get the other records. I'm already using the GetRows() method with an actual query and still with an ADODB recordset and it works perfectly. Building a recodset from scratch seems less easy.
I need to put all my data in an object to work with it. But even if I want to use only a recordset, I cannot access to all data in it. Very fustrating... something I'm missing here...
Error I get: either bof or eof is true or the current record has been deleted
Thanks in advance,
Public Function GetFDBData() As Boolean
Dim filtersView As New ADODB.Recordset
Dim rsFields(1) As Object
Dim fieldsAPT(3, 1) As Object
Dim dataView As Object
Dim i As Integer
rsFields(0) = "Field Name"
rsFields(1) = "Filter"
fieldsAPT(0, 0) = "ISIN"
fieldsAPT(0, 1) = "=CA89*"
fieldsAPT(1, 0) = "Currency"
fieldsAPT(1, 1) = "=CAD"
fieldsAPT(2, 0) = "Line"
fieldsAPT(2, 1) = "=Bond"
fieldsAPT(3, 0) = "Redemption Date"
fieldsAPT(3, 1) = "=20230*"
Try
'Build the recordset containing APT fields and filters (in the same variable fieldsAPT)
filtersView.CursorLocation = ADODB.CursorLocationEnum.adUseClient
filtersView.Fields.Append(rsFields(0), ADODB.DataTypeEnum.adVarChar, 30)
filtersView.Fields.Append(rsFields(1), ADODB.DataTypeEnum.adVarChar, 30)
filtersView.Open(, , ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockOptimistic)
Dim fieldAPT(1)
For i = 0 To UBound(fieldsAPT)
fieldAPT(0) = fieldsAPT(i, 0)
Console.WriteLine(fieldAPT(0)) 'Works fine
fieldAPT(1) = fieldsAPT(i, 1)
Console.WriteLine(fieldAPT(1)) 'Works fine
filtersView.AddNew(rsFields, fieldAPT)
filtersView.Update()
Console.WriteLine(filtersView.RecordCount) 'I can see 1 2 3 4 no problem here
Next i
Dim xx As Integer = filtersView.RecordCount 'xx is 4 as expected
Console.WriteLine("xx: " & xx)
filtersView.MoveFirst() 'Will move to the first record or whatever record
'dataView = filtersView.GetRows() 'I expected this line to work, but same results
For i = 0 To xx - 1
dataView = filtersView.GetRows()
Console.WriteLine(dataView(i, 0).ToString) 'ISIN, normal
Console.WriteLine(filtersView.RecordCount) 'Still equals 4, normal
Console.WriteLine(filtersView.BOF) 'False, normal
Console.WriteLine(filtersView.EOF) 'True, which is NOT normal
Console.WriteLine(filtersView.AbsolutePosition) 'Get -3 not sure why (position 1 related to 4???)
Console.WriteLine(filtersView.MaxRecords) 'Get 0 not sure why
filtersView.MoveNext() '!!!! Here is where it fails !!!! Cannot go more than i=0
Next i
GetFDBData = True
Catch ex As Exception
MsgBox(ex.Message)
GetFDBData = False
Finally
'Clear memory
filtersView.Close()
End Try
End Function
Also, if I do this,
Dim xx As Integer = filtersView.RecordCount 'xx is 4 as expected
Console.WriteLine("xx: " & xx)
filtersView.MoveLast()
Instead of
Dim xx As Integer = filtersView.RecordCount 'xx is 4 as expected
Console.WriteLine("xx: " & xx)
filtersView.MoveFirst()
It will return "Redemption date" in the for loop after. Which makes sense because it is the last record. But puting movefirst even after does'nt solve the issue... still one row only. So the data is there, but I really can't extract one line and one line only...
Try changing your cursor type to adOpenDynamic
EDIT: OK,your line
dataView = filtersView.GetRows()
is causing your cursor to travel to the end of the recordset, try moving it outside your loop and following it with a new MoveFirst like so
filtersView.MoveFirst() 'Will move to the first record or whatever record
'dataView = filtersView.GetRows() 'I expected this line to work, but same results
dataView = filtersView.GetRows()
filtersView.MoveFirst()
Dim sTemp As String = ""
For i = 0 To xx - 1
'Console.WriteLine(dataView(i, 0).ToString) 'ISIN, normal
Console.WriteLine(filtersView.RecordCount) 'Still equals 4, normal
Console.WriteLine(filtersView.BOF) 'False, normal
Console.WriteLine(filtersView.EOF) 'True, which is NOT normal
Console.WriteLine(filtersView.AbsolutePosition) 'Get -3 not sure why (position 1 related to 4???)
Console.WriteLine(filtersView.MaxRecords) 'Get 0 not sure why
sTemp = sTemp & "(" & dataView(0, i).ToString & ", " & dataView(1, i).ToString & ")"
filtersView.MoveNext() '!!!! Here is where it fails !!!! Cannot go more than i=0
Next i
Console.WriteLine(sTemp)
You can verify that by checking the value of filtersView.AbsolutePosition immediately before and after your call to GetRows
Also, you are reversing rows and columns in dataView, move i to the second subscript position. I put it in a temporary string to make it easier to view in the debugger.

Resources