How can I get SQL 2008 R2 to store the CR/LF embedded in a string (so 2 paragraphs, or possibly multiple CR/LFs) into a field of a record being inserted programmatically vb.net? Not all records have a CR/LF so I cannot just add them to every record. +Char(13)+char(10) that I could split with a charArrary.
UPDATE: This appears to be the actual problem: the XML parser will convert CR/LF to LF only for consistency. I am passing data to and from a web service and this seems to be where the CR is being lost. This is by W3 standard.
W3.org Section: 2.11 End-of-Line Handling
These strings are coming from an Access DB and have the CR/LF already included in a multi-paragraph field of the record. I would like to just pass them straight in, but SQL is converting them to spaces.
In VS Sql Editor the record appears to store 20:20 Hex where the CR/LF should reside. The string actually should have Char(13) & Char(10) or 0x0D0A but it does not.
I see the same results even editing or inserting the record directly via SSMS or the VS SQL Editor. The records were originally submitted via a web service but I have eliminated that for testing. I read that the XML parser will also convert CR/LF to LF only for consistency.
I am not able to show the actual query. But the adapter is built here and populated and passed back to my app via a web service call. This process works for all but the records that have CRLF in them.
Dim strConnection As String
strConnection = ConfigurationManager.ConnectionStrings("ConnectionStringMyDB").ConnectionString
Dim myConnection As New SqlConnection(strConnection)
Dim myCommand As New SqlCommand(strSQL, myConnection)
' Access file name
myCommand.Parameters.AddWithValue("#dbName", OleDbType.VarChar).Value = dbName
' Table in Access DB
myCommand.Parameters.AddWithValue("#tableName", OleDbType.VarChar).Value = tableName
myConnection.Open()
' Create the DataAdapter
Dim myDataAdapter As New SqlDataAdapter()
myDataAdapter.SelectCommand = myCommand
' Populate the DataSet and close the connection
Dim myDataSet As New DataSet()
myDataAdapter.Fill(myDataSet)
myConnection.Close()
Return myDataSet
Processsing in my app after assigning the dataset to a table.
For Each row As DataRow In myTable.Rows
Dim stringVal As String = row(columnName).ToString()
' Eventually added this to see that the row was adding 2 spaces after the carriage return
Dim cstringVal() As Char = stringVal.ToCharArray
Dim csearchValue() As Char = searchValue.ToCharArray
' Also added this code
Dim line_array1 As [String]() = stringVal.Split(vbCr & vbLf.ToCharArray())
Dim line_array2 As [String]() = searchValue.Split(vbCr & vbLf.ToCharArray())
' line_Array2 consistently IDs the vbCRLF, line_array1 never does.
' Originally tried
If row(columnName) = searchValue Then
return True
End If
' Tried this
If stringVal = searchValue Then
Return True
End If
' And this
If String.Compare(stringVal, searchValue, False) = 0 Then
Return True
End If
Next
Return False
Thanks
Maybe the problem is UNICODE. By my experience there is no problem with storing CRLF, but there can be problem UNICODE <-> ASCII.
Please try
Dim cmd as SQLCommand
cmd.CommandText = "insert into MyTable(fld) values (N'" + VariableContainingCRLF +"')"
cmd.ExecuteNonQuery
Or
Dim cmd as SQLCommand
cmd.CommandText = "insert into MyTable(fld) values (#param)"
cmd.Parameters.Add("#param", SqlDbType.NVarChar, 50).Value = VariableContainingCRLF
cmd.ExecuteNonQuery
Letter N before a string or NVarChar is crucial. DataAdapter introduces just other confusing layer.
You are confusing data storage and data display and editing.
I just verified that SQL Server does store CRLF in a VARCHAR field:
insert into MyTable (VarcharField)
values ('A'+CHAR(13)+'B')
, ('A'+CHAR(13)+CHAR(10)+'B')
, ('A
B')
by checking the ASCII() codes of the inserted strings
SELECT VarcharField, LEN(VarcharField),
, ASCII(substring(VarcharField, 2, 1))
, ASCII(substring(VarcharField, 3, 1))
FROM MyTable
The CR and CRLF are displayed as spaces, but they are still stored as 0x0D and 0x0A, or 13 and 10.
Related
Can someone please explain to me when the "size" column wont work for comparison but I can replace the ID column in my code and it works perfectly fine. Perhaps my formatting of the access database column for Size isnt correct?
I am basically just trying to see if the key and value in my dictionary match the conditions in the access database and if so to write one text, if not write another. The error I keep getting when I have size in my code is:
An unhandled exception of type 'System.Data.OleDb.OleDbException' occurred in System.Data.dll IErrorInfo.GetDescription failed with E_FAIL(0x80004005).
For Each KeyPair In dict
Dim key As String
Dim value As Integer
key = KeyPair.Key
value = KeyPair.Value
Dim sqlQry As String
sqlQry = "SELECT Item, Size FROM [Table] WHERE Item = '" & key & "'AND Size>" & value & " "
Console.WriteLine(sqlQry)
Dim topDecision As String
Dim cmd As OleDbCommand
cmd = New OleDbCommand(sqlQry, myconnection)
Dim myreader As OleDbDataReader
myreader = cmd.ExecuteReader()
If myreader.Read() Then
topDecision = "Order"
Else
topDecision = "Dont"
End If
myreader.Close()
Next
Connections and some other database objects provided by ADO.net use unmanaged code internally. They provide a .Dispose method where they release these resources. It is up to the coder to call the .Dispose method. Fortunately, .net provides Using...End Using blocks that handle this for us. Connections, commands and readers should be declared in the method where they are used so they can be properly closed and disposed.
Don't concatenate strings to build sql queries. Use parameters to avoid sql injection. We only need a single command and a single ParametersCollection. Only the values of the parameters change inside the loop.
A special note for OleDb parameters. The names of the parameters are ignored. The position of the parameter in the sql query should match the order that they are added to the ParametersCollection.
Declare KeyPair As KeyValuePair so you can access .Key and .Value properties.
I used a StringBuilder to collect the messages from your code. A StringBuilder is mutable (changeable) whereas a String is not. If I used a String the compiler would have to throw away a string and create a new one on each iteration. The garbage collector would be kept busy.
I used an interpolated string indicated by the $ before the string. It allows us to insert variables directly into the string if they are surrounded by braces { }.
If you follow this sample, be sure the text box at the end has Multiline = True.
Private Sub OPCode()
Dim sqlQry = "SELECT Item, Size FROM [Table] WHERE Item = #Key AND Size > #Value;"
Dim sb As New StringBuilder
Using cn As New OleDbConnection("Your connection string"),
cmd As New OleDbCommand(sqlQry, cn)
cmd.Parameters.Add("#Key", OleDbType.VarChar, 100)
cmd.Parameters.Add("#Value", OleDbType.Integer)
cn.Open()
For Each KeyPair As KeyValuePair(Of String, Integer) In dict
cmd.Parameters("#Key").Value = KeyPair.Key
cmd.Parameters("#Value").Value = KeyPair.Value
Dim topDecision As String
Using myreader = cmd.ExecuteReader()
If myreader.Read() Then
topDecision = "Order"
Else
topDecision = "Dont Order"
End If
End Using
sb.AppendLine($"{KeyPair.Key} - {topDecision}")
Next
End Using
TextBox1.Text = sb.ToString
End Sub
How do I retrieve an ID field that is an AutoNumber and has been given an alphanumeric Format, e.g., 'ER001'?
I'm using Access for backend and VB 2010.
My code so far only returns the last number of the ID Column, e.g., 1 instead of ER001.
Dim SQL As String = "SELECT ID FROM ReqItemList WHERE ReqItem = " & inputin & " "
I believe that the confusion here is because the AutoNumber field "has alphanumeric format". If the table design looks like this
then the Format property "ER"000 for the ID field will cause it to appear in Access forms and datasheet views as something like ER001.
However, in Design View (the first screenshot) notice that the field is still an AutoNumber field and its "Field Size" is Long Integer. The values themselves are just numbers; they are merely being formatted as alphanumeric in the Access user interface.
So the behaviour you are seeing in your VB.NET application is "normal". If you run the query
Dim SQL As String = "SELECT ID FROM ReqItemList WHERE ReqItem=?"
Using cmd = New OleDbCommand(SQL, con)
cmd.Parameters.Add("?", OleDbType.VarWChar).Value = "foo"
Dim rtn = cmd.ExecuteScalar()
End Using
then you will get the Integer value 1, not the String value "ER001". If you want to have the value appear in your VB.NET forms as ER001 you will need to apply the formatting in your VB.NET code.
Similarly, if you want to search by ID then you will have to supply the unformatted numeric value. That is
Dim SQL As String = "SELECT ReqItem FROM ReqItemList WHERE ID=?"
Using cmd = New OleDbCommand(SQL, con)
cmd.Parameters.Add("?", OleDbType.Integer).Value = 1
Dim rtn As String = cmd.ExecuteScalar()
End Using
will return foo, whereas
Dim SQL As String = "SELECT ReqItem FROM ReqItemList WHERE ID=?"
Using cmd = New OleDbCommand(SQL, con)
cmd.Parameters.Add("?", OleDbType.VarWChar).Value = "ER001"
Dim rtn As String = cmd.ExecuteScalar()
End Using
will fail with "Data type mismatch in criteria expression" because ID is really a number, not a text value.
When I try to do an import from an Excel document the comments get truncated. I have checked the usually issue that the Table would be limited but is set as:
Comments ... nvarchar(MAX)
Sample of the code, please note even running the code in Debug mode I can see the parameter is truncated before it even goes to the stored procedure.
Dim excelConnectionString As String = (Convert.ToString("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=") & vFileNameFolder) + "; Extended Properties='Excel 12.0;HDR=YES;IMEX=1;';"
'#### Upload, Rename and save file
'#### Open Excel to Parse here
Dim ds As New DataSet
Dim oleda As New OleDbDataAdapter()
Dim cmdExcel As New OleDbCommand()
'#### End - Open Excel to Parse here
Dim vActionRef As String = ""
Try
Dim excelConnection As New OleDbConnection(excelConnectionString)
With cmdExcel
.CommandText = "Select * from [Portal$A1:BB9999]" 'Names we want to select and the name of the sheet
.CommandType = CommandType.Text
.Connection = excelConnection
End With
excelConnection.Open()
oleda = New OleDbDataAdapter(cmdExcel)
oleda.Fill(ds, "dataExcel")
If ds.Tables("dataExcel").Rows.Count > 0 Then
'#### Stored procedure details
Dim connection As SqlConnection
Dim commandSQL As New SqlCommand
Dim FRAUPRN As String = ""
Dim ConnectionString As String = System.Configuration.ConfigurationManager.ConnectionStrings("SQLLocal").ToString()
'########### End - Stored procedure details
'Set date once
Dim vDate As Date
vDate = DateTime.Now.AddDays(0)
connection = New SqlConnection(ConnectionString)
connection.Open()
'Dims for error handling and checking for invalid characters
Dim iImported As Integer
For j As Integer = 0 To ds.Tables("dataExcel").Rows.Count - 1 ' counted rows so loop through, ignores first row with names in
If (IsDBNull(ds.Tables("dataExcel").Rows(j)("UPRN"))) Then
'skip
Else
iImported = iImported + 1
'Bring the data across, the rows(i)("xxx") must match a name on the Excel sheet but DOES NOT have to be in order
With commandSQL
.Parameters.Clear()
.Connection = connection
.CommandText = "spAddCSVDataLine" 'Stored procedure here
If Trim(ds.Tables("dataExcel").Rows(j)("Comments")) = "0" Then
.Parameters.AddWithValue("Comments", " ")
Else
' .Parameters.AddWithValue("Comments", If(IsDBNull(ds.Tables("dataExcel").Rows(j)("Comments")), "", Trim(ds.Tables("dataExcel").Rows(j)("Comments"))))
Dim vComments As String
vComments = ds.Tables("dataExcel").Rows(j)("Comments")
.Parameters.AddWithValue("Comments", vComments)
Session.Item("Comments") = Session.Item("Comments").ToString & "//" & vComments
End If
I have looked at similar questions such as ADO is truncating Excel data which talks about numerical issues but am struggling to find the reason why I am losing data before I export the data. 'Common sense' says excel is not passing over more than 255 characters but then this is programming!
I've had all sorts of problems with the JET/Ace DB engine truncating and doing other sorry-ass guesses at data type. Check out this Microsoft article that talks a bit about how JET uses only the first 8 records to determine field length (http://support.microsoft.com/kb/189897/en-us). You can edit a registry setting to change how many records it will scan to determine field length, but the results still seem to be hit or miss for folks.
You might also find some luck in creating a dummy record at the top of the excel sheet that contains a comment with the maximum number of characters of any of your comments. Then just delete that one record after it comes through. Again... results seem to be mixed here.
How do you use SQL to put data into an empty table? So far in my code I have taken the data from an SQL table and then have put it into a Text Box using the following code:
Dim query As String = "SELECT Pronunciation, Character FROM [Katakana List] WHERE Pronunciation='" & pronunciation & "';"
Dim instruction = New SqlCommand(query, sqlCon)
Dim da As New SqlDataAdapter
da.SelectCommand = instruction
da.Fill(Katakana)
Textbox1.text=DT.row(0)("column")
Now that the data is held in the text box, how would I do the reverse of this process to put the data into an empty table. It would help if someone could give me an example of the query I could use to put the data back in.
If you want update data which you get from query before, then use UPDATE-query
If you want insert brand new data then use INSERT - query
'For updating existing data
Dim query As String = "UPDATE [Katakana List] SET Character = #NewCharacter WHERE Pronunciation=#Pronunciation"
'For Inserting new data
Dim query As String = "INSERT INTO [Katakana List] (Character) VALUES (#NewCharacter);"
Using instruction As New SqlCommand(query, sqlCon)
'Better practice to use parameters in query
instruction.Parameters.AddWithValue("#Pronunciation", pronunciation)
instruction.Parameters.AddWithValue("#NewCharacter", Textbox1.text)
instruction.ExecuteNonQuery()
End Using
If you want to set the data in the textbox into datatable just do it like this :
DT.row(0)("column") = Textbox1.text
if you want to enter it into database create query to do so , something like this :
Dim query As String = "Insert Into TableName(col1) Values('"& Textbox1.text &"');"
Dim command = New SqlCommand(query, sqlCon)
command.ExecuteNonQuery()
I'm trying to create a program which has a datagridview, when the user clicks on a cell in the view, it then looks in a SQL database, grabs information from other fields in the same record, and automatically fills corresponding text boxes (done by manipulating the name of the field) in the form.
For some reason however, I'm getting an error message saying:
"InvalidOperationException was unhandled"
"No Data exists for the row / column"
Here is the code relevant to this part of the program:
Private Sub DataGridView1_CellMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles dgvResults.CellMouseClick
' Set values in the text boxes to both corresponding to the film.
Dim strFields() As String = {"ID", "fName", "fGenre", "fSynopsis", "fAgeRating", "fActorsActresses", "fWebRating", "fNoReservations", "fWeeksRunning"}
Dim Con = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=ApplicationData.accdb;Persist Security Info=False;")
Con.Open() 'Open the connection
Dim Cmd As New OleDbCommand(StringBuilderCommand("*", "Films", dgvResults.CurrentCell.Value, "fName"), Con) 'Create a string by calling the StringBuilderCommand to combine the parameters together with quotes.
Cmd.CommandType = CommandType.Text
Dim Rdr As OleDbDataReader = Cmd.ExecuteReader()
Dim intCount As Integer = 4 ' Create a loop variable.
Do While Rdr.Read() Or intCount < 6 ' While this statement is 'TRUE', e.g. there is a valid record.
strResult = "txt" & strFields(intCount).Replace("f", "") 'Remove any instances of 'f', e.g. the prefix of the string.
txtActorsActresses.Text = StringBuilderCommand("*", "Films", dgvResults.CurrentCell.Value, "fName")
Me.Controls(strResult).Text = Rdr.Item(strFields(intCount)) ' Suspect the error lies here.
'Set the text-box to the correct value from the database.
'This will allow me to go through several text boxes, and grab their corresponding values from the database.
intCount = intCount + 1
'Current error is because it cannot find any data beyond the first field taken.
'I have no idea why this is. But if I change the starting intCount value, it will successfully take a different value.
Loop
Rdr.Close() 'Cleaning up.
Cmd.Dispose()
Con.Close()
WebBrowser1.Navigate(dgvResults.CurrentCell.Value.Replace(" ", ".") & ".movie.poster.new.jpg.to") 'Grab the movie poster off the internet corresponding to the films name.
End Sub
Private Function StringBuilderCommand(Field, Table, CurrentCellValue, SearchParameter)
'Creates a suitable SQL string.
Dim MyStringBuilder As New StringBuilder("SELECT ")
MyStringBuilder.Append("*") ' Append the parameter 'Field'.
MyStringBuilder.Append(" FROM ") ' Append the SQL command 'FROM'.
MyStringBuilder.Append(Table) ' Append the parameter 'Table'.
MyStringBuilder.Append(" WHERE ") ' Append the SQL command 'WHERE'.
MyStringBuilder.Append(SearchParameter) ' Append the parameter 'SearchParameter'.
MyStringBuilder.Append("=""")
MyStringBuilder.Append(CurrentCellValue) ' Append the parameter 'CurrentCellValue', representing the cell selected.
MyStringBuilder.Append("""") 'Append a quotation mark.
Return MyStringBuilder.ToString() ' Return it to the main program.
End Function
Database table being connected to:
A view of the error as it looks in Visual Studio 2012 Express:
The value of 'dgvResults.CurrentCell.Value' is the name of a film taken from the database (e.g. "12 Years a Slave").
What am I doing wrong?
Thanks,
C.
The problem is caused by the value of strFields(intCount) you are passing to the reader. It is not a valid column index.
You probably want to loop on the fields before looping again on DataReader(), like:
Do While Rdr.Read()
For intCount as Integer = 4 to 6
strResult = "txt" & strFields(intCount).Replace("f", "")
txtActorsActresses.Text = StringBuilderCommand("*", "Films", dgvResults.CurrentCell.Value, "fName")
Me.Controls(strResult).Text = Rdr.Item(strFields(intCount))
Next
Loop
I removed the Dim intCount As Integer = 4 because it is no longer needed because of the for next loop.