I am iterating through some rows/cells in an Excel sheet and some of the cells are blank. When I try to do the insert, if a cell contains no data, it advises me that that particular parameter has no default value. In Access, I have set the default value to "=Null" but I still receive the error. Do I have to do an If statement as shown below for every parameter in order to prevent errors? I'd like to clean up my code if possible.
If worksheet1.GetValue(i, 14) Is Nothing Then
cmd.Parameters.Add("#Param1", OleDbType.Char).Value = DBNull.Value
Else
cmd.Parameters.Add("#Param1", OleDbType.Char).Value = worksheet1.GetValue(i, 14)
End If
In my experience (albeit C#), yes you do. Interop (which is what I'm assuming you're using although I don't recognise the GetValue() call) usually throws an exception when you try to get data from an empty cell without first checking. The way I've handled it is to wrap the code in a method and just call it each time (sorry, my VB is a little rusty):
Public Function GetCellContents(column As Integer, row As Integer) As String
If worksheet1.GetValue(column, row) Is Nothing Then
Return ""
Else
Return worksheet1.GetValue(column, row)
End If
End Function
And then you can just do:
cmd.Parameters.Add("#Param1", OleDbType.Char).Value = GetCellContents(i, 14);
Related
I have a piece of code within a larger script that simply allocates a value to "i" based on a match. The idea being I want it to give the match value if the value entered is found, or 0 if not. If it's 0, I can then exit sub with a message to the user. However, any time the match finds a null value, it just kills the sub, instead of it being handled as part of the iferror I've introduced. I've tried various manners of checking (using iif(iserror) for example) but none seem to work.
Code causing the issue is below:
i = Application.WorksheetFunction.IfError(Application.WorksheetFunction.Match(username, EL.Range("A:A"), 0), 0)
i is dim as an integer
Username is dim as a string, and comes from an inputbox
EL is dim as a worksheet, and contains the correct info.
This has absolutely no issues if I introduce any name that exists, it only fails as soon as I input a name that does not work, and I'm sort of stumped as to why. I see no reason for it to fail, but feel like I'm missing something simply and in-my-face.
Use this instead. Using Application instead of WorksheetFunction enables the error to be trapped and tested.
i = Application.IfError(Application.Match(UserName, EL.Range("A:A"), 0), 0)
I would use a slightly different approach to trap an error on Application.Match function:
Dim i As Variant
i = Application.Match(UserName, EL.Range("A:A"), 0)
' if Match wasn't able to found a "match"
If IsError(i) Then i = 0
I am searching a database and pulling results from it. Before displaying it in WPF I am checking the contents of the text in a field called PrimarySponsor which can be (1) blank/null (2) number at 3rd character (3) persons name. I am currently using Char.IsNumber to check option 2 if there is a number at position 4.
If reader("PrimarySponsor") Is DBNull.Value Then
resultxPrimSpon = ""
ElseIf Char.IsNumber(reader("PrimarySponsor"), 3) Then
resultxPrimSpon = "Terminated"
Else
resultxPrimSpon = reader("PrimarySponsor")
End If
Before I put the Char.IsNumber check in I was getting 4 results displaying. When i add the Char.IsNumber code I only get 2 results along with the error;
Error while connecting to SQLServer.Sepcified argument was out of the range of valid values. Parameter name: index.
Anyone have any ideas about why this is happening or how to work around it?
It's not clear where you get that error because Char.IsNumber is not a sql-server method. So i assume that it's a custom message from you. However, the "Specified argument was out of the range" is documented:
ArgumentOutOfRangeException: index is less than zero or greater than
the last position in s.
So it seems that at least one of the strings is shorter than 4 characters. In general you should store the reader values in a variable of the correct type if you have to access it more than once. In this case in a String-variable.
But it's also a good idea to create a custom type that has all properties. Then you can add all to a List(Of T). Here's an example:
Public Class Sponsor
Public Property PrimarySponsor As String
End Class
Of course you could also fill a List(Of String) instead of a List(Of Sponsor). Then you don't need to create a new type. But i assume that you have more than one column in the table. Using a custom type increases readability and maintainability much.
....
Dim allSponsors As New List(Of Sponsor)
Using reader = command.ExecuteReader()
If reader.HasRows Then
Dim primSponsorColumnIndex = reader.GetOrdinal("PrimarySponsor")
While reader.Read
Dim sponsor As New Sponsor()
If reader.IsDBNull(primSponsorColumnIndex) Then
sponsor.PrimarySponsor = ""
Else
sponsor.PrimarySponsor = reader.GetString(primSponsorColumnIndex)
If sponsor.PrimarySponsor.Length >= 4 AndAlso _
Char.IsDigit(sponsor.PrimarySponsor(3)) Then
sponsor.PrimarySponsor = "Terminated"
End If
End If
allSponsors.Add(sponsor)
End While
End If
End Using
First use DataReader.IsDBNull to check if the value is Null. Then check if Length >= 4 before you use Char.IsDigit(sponsor.PrimarySponsor(3)) to avoid the ArgumentOutOfRangeException.
Difference between Char.IsDigit() and Char.IsNumber() in C#
I am trying to write a simple UDF, which is supposed to loop through each of the cells of a given_row, and pick up those cells which do not have any precedent ranges, and add up the values.
Here is the code:
Public Function TotalActualDeductions(given_row As Integer) As Integer
Total_Actual_Deduction = 0
For present_column = 4 To 153
Set precedent_range = Nothing
If Cells(2, present_column) = "TDS (Replace computed figure when actually deducted)" Then
On Error Resume Next
Set precedent_range = Cells(given_row, present_column).Precedents
If precedent_range Is Nothing Then
Total_Actual_Deduction = Total_Actual_Deduction + Cells(given_row, present_column)
End If
End If
Next
TotalActualDeductions = Total_Actual_Deduction
End Function
If I try to run it by modifying the top declaration, from:
Public Function TotalActualDeductions(given_row As Integer) As Integer
to:
Public Function TotalActualDeductions()
given_row = 4
then it runs successfully, and as expected. It picks up exactly those cells which match the criteria, and all is good.
However, when I try to run this as a proper UDF from the worksheet, it does not work. Apparently, excel treats those cells which have no precedents, as though they have precedents, when I call the function from the worksheet.
I don't know why this happens, or if the range.precedents property is supposed to behave like this.
How can this be fixed?
After a lot of searching, I encountered this:
When called from an Excel VBA UDF, Range.Precedents returns the range and not its precedents. Is there a workaround?
Apparently, "any call to .Precedents in a call stack that includes a UDF gets handled differntly".
So, what I did was use Range.Formula Like "=[a-zA-Z]" , because it satisfied my simple purpose. It is in no way an ideal alternative to the range.precedents property.
Foe a more detailed explanation, please visit that link.
I was wonder how to convert this line of code to vb.net. I changed the dataset to recordset and it is indeed a function. When i convert It gave me this error. The dataset is filled with values from Database Its just that this "!" is the main error can anyone tell me what that means in vb6? The error that came out was"Dataset Cannot Be index because there is no default Properties"
'getting values from database procedure
If priRecordSet!CodeStatus Then
IfCodeStatus = True
Else
IFCodeStatus = False
End If
Return IfCodeStatus
To access a particular column value of a particular row, use
myTableData.Rows(rowNumber)(columnNumber)
or
myTableData.Rows(rowNumber).Item(columnNumber)
Update
I decided to iterate through the Data.DataTable and trimmed the values there.
Utilizing SirDemon's post, I have updated the code a little bit:
Sub test(ByVal path As String)
Dim oData As GSDataObject = GetDataObj(path)
EmptyComboBoxes()
Dim oDT As New Data.DataTable
Try
Dim t = From r In oData.GetTable(String.Format("SELECT * FROM {0}gsobj\paths ORDER BY keyid", AddBS(path))) Select r
If t.Count > 0 Then
oDT = t.CopyToDataTable
For Each dr As Data.DataRow In oDT.Rows
dr.Item("key_code") = dr.Item("key_code").ToString.Trim
dr.Item("descript") = dr.Item("descript").ToString.Trim
Next
dataPathComboBox.DataSource = oDT
dataPathComboBox.DisplayMember = "descript"
dataPathComboBox.ValueMember = "key_code"
dataPathComboBox.SelectedIndex = 0
dataPathComboBox.Enabled = True
End If
Catch ex As Exception
End Try
End Sub
This works almost as I need it to, the data is originally from a foxpro table, so the strings it returns are <value> plus (<Field>.maxlength-<value>.length) of trailing whitespace characters. For example, a field with a 12 character length has a value of bob. When I query the database, I get "bob_________", where _ is a space.
I have tried a couple of different things to get rid of the whitespace such as:
dataPathComboBox.DisplayMember.Trim()
dataPathComboBox.DisplayMember = "descript".Trim.
But nothing has worked yet. Other than iterating through the Data.DataTable or creating a custom CopyToDataTable method, is there any way I can trim the values? Perhaps it can be done in-line with the LINQ query?
Here is the code I have so far, I have no problem querying the database and getting the information, but I cannot figure out how to display the proper text in the ComboBox list. I always get System.Data.DataRow :
Try
Dim t = From r In oData.GetTable("SELECT * FROM ../gsobj/paths ORDER BY keyid") _
Select r
dataPathComboBox.DataSource = t.ToList
dataPathComboBox.SelectedIndex = 0
'dataPathComboBox.DisplayMember = t.ToList.First.Item("descript")
dataPathComboBox.Enabled = True
Catch ex As Exception
Stop
End Try
I know that on the DisplayMember line the .First.Item() part is wrong, I just wanted to show what row I am trying to designate as the DisplayMember.
I'm pretty sure your code tries to set an entire DataRow to a property that is simply the name of the Field (in a strongly type class) or a Column (in a DataTable).
dataPathComboBox.DisplayMember = "descript"
Should work if the DataTable contains a retrieved column of that name.
Also, I'd suggest setting your SelectedIndex only AFTER you've done the DataBinding and you know you actually have items, otherwise SelectedIndex = 0 may throw an exception.
EDIT: Trimming the name of the bound column will trim just that, not the actual bound value string. You either have to go through all the items after they've been bound and do something like:
dataPathComboBox.Item[i].Text = dataPathComboBox.Item[i].Text.Trim()
For each one of the items. Not sure what ComboBox control you're using, so the item collection name might be something else.
Another solution is doing that for each item when it is bound if the ComboBox control exposes an onItemDataBound event of some kind.
There are plenty of other ways to do this, depending on what the control itself offers and what you choose to do.
DisplayMember is intended to indicate the name of the property holding the value to be displayed.
In your case, I'm not sure what the syntax will by since you seem to be using a DataSet, but that should be
... DisplayMember="Item['descript']" ...
in Xaml, unless you need to switch that at runtime in which case you can do it in code with
dataPathComboBox.DisplayMember = "Item['descript']"
Again, not 100% sure on the syntax. If you are using a strongly typed DataSet it's even easier since you should have a "descript" property on your row, but given hat your error indicates "System.DataRow" and not a custom type, I guess you are not.
Because I can't figure out the underlying type of the datasource you are using I suggest you to change commented string to
dataPathComboBox.DisplayMember = t.ElementType.GetProperties.GetValue(0).Name
and try to determine correct index (initially it is zero) in practice.