Import data from Excel to SQL Server using vb.net - sql-server

I am importing data from Excel into a SQL Server database using vb.net. In my Excel file, in column bNumber, there are values of different types i.e some are numbers and some are text:
Telenorx
Telenorx
8
97150219924
97150219924
97150219924
97150219924
Easypayx
92
When I select the data from Excel through OleDbCommand, it retrieves numbers correctly but text values as blank.
In Excel, the column's data type is General.
This is my code to retrieve data from Excel.
excelConn = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data
Source= " + OpenFileDialog1.FileName + ";Extended Properties=""Excel 12.0
Xml;HDR=Yes""")
Dim oleDbCommand As OleDbCommand = New OleDbCommand("Select bNumber from
[Sheet1$]", excelConn)
excelConn.open()
Dim dataReader = oleDbCommand.ExecuteReader
dataReader.read()

This is not necessarily a solution for your case yet would I did was created a SQL-Server table with bNumber as nvarchar, used SQL-Server Management Studio to export to Excel where I placed the Excel file in the bin\Debug folder of the project. Using the code below all rows returned properly (as we have a string column strings are returned).
The key here is using IMEX=1 in the connection string, Excel can be finicky, this may or may not resolve the issue.
Imports System.Data.OleDb
Public Class Operations
Public Function GetData(ByVal FileName As String) As List(Of String)
Dim valueList As New List(Of String)
Using cn As New OleDbConnection With
{
.ConnectionString = ConnectionString(FileName)
}
Using cmd As OleDbCommand = New OleDbCommand("SELECT bNumber FROM [Table_1$]", cn)
cn.Open()
Dim reader As OleDbDataReader = cmd.ExecuteReader
While reader.Read
valueList.Add(reader.GetString(0))
End While
End Using
End Using
Return valueList
End Function
Public Function ConnectionString(ByVal FileName As String) As String
Dim Builder As New OleDbConnectionStringBuilder
If IO.Path.GetExtension(FileName).ToUpper = ".XLS" Then
Builder.Provider = "Microsoft.Jet.OLEDB.4.0"
Builder.Add("Extended Properties", "Excel 8.0;IMEX=1;HDR=Yes;")
Else
Builder.Provider = "Microsoft.ACE.OLEDB.12.0"
Builder.Add("Extended Properties", "Excel 12.0;IMEX=1;HDR=Yes;")
End If
Builder.DataSource = FileName
Return Builder.ConnectionString
End Function
End Class
Form code
Private Sub Button3_Click(sender As Object, e As EventArgs) _
Handles Button3.Click
Dim ops As New Operations
Dim fileName As String = IO.Path.Combine(
AppDomain.CurrentDomain.BaseDirectory, "Downloaded.xlsx")
Dim valueList As List(Of String) = ops.GetData(fileName)
For Each value As String In valueList
Console.WriteLine(value)
Next
End Sub
Results in the IDE Output window
Table structure
Worksheet
EDIT: The following link points to a MSDN code sample for working with SpreadSheetLight library. Once downloaded, set startup form to StackOverFlow1QuestionMixedTypesForm. Right click on the solution in solution explorer and select "Restore NuGet Packages", now build and run the project. There are two buttons on the form, first does mixed types for Sheet1 while button two is a variant of the same data laid out differently in Sheet2.
Code sample https://code.msdn.microsoft.com/Alternate-methods-to-work-4c52c4a2

Related

SQL Server database population pre-existing Data Table and fields (FORM). NO database file

Here is my general understanding of database from what I read so far: Save / Update / Delete to pre-existing file made that binds to form thru SQL.
Here is what I am trying to do - I have a pre-made Data Table in Form with all columns defined. Once app is closed or certain functions ran, I need that data to be saved / updated in SQL (on local). Once app is open I need all that data to be preserved.
So far I have NOT found a single solution to it anywhere most refer to binding to an existing file. When I worked with Excel data transfer cells had to be defined and referenced in form for population.
My assumption is when a database from VB.NET is used, table with values can be created automatically saved/loaded/updated. However this is only my assumption since I never worked with SQL before. I am not sure if I need to manage an actual database file I created with all the values and then bind them to data table. For example DataTable cell XX to database column XX.
Here is what I done so far I have created database and added to my project. I tried few codes and I keep getting Dataset Empty even though there is Data in Table I tried to use DataTable as well but so far nothing has worked.
Please suggest on what I am doing wrong also additional information regards to databases will be great. As per previous I do know how binding works when actual file exist. But creating and managing is confusing to me since I keep thinking there should be a binding file.
Dim connetionString As String
Dim sqlCnn As SqlConnection
Dim sqlCmd As SqlCommand
Dim adapter As New SqlDataAdapter
Dim ds As New DataSet
Dim sql As String
connetionString = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Data_Ant.mdf;Integrated Security=True;Connect Timeout=30"
sql = "SELECT BN FROM DataTable" ' BN is my column name and DataTable is the name of my Table where data gets populated. This is also confusing to me How does it know which value is what? Is there are space/word/characters requirements?
' adapter.TableMappings.Add("DataTable", sql)
If ds.Tables.Count > 0 Then
sqlCnn = New SqlConnection(connetionString)
Try
sqlCnn.Open()
sqlCmd = New SqlCommand(sql, sqlCnn)
adapter.SelectCommand = sqlCmd
adapter.Update(ds)
adapter.Dispose()
sqlCmd.Dispose()
sqlCnn.Close()
Catch ex As Exception
MsgBox("Can not open connection !" & vbCrLf & Err.Description)
End Try
ElseIf ds.Tables.Count = 0 Then
MsgBox("Empty data")
End If
End Sub
Code I use to Create /Save Database. As per previous all columns/formats are pre-made, loaded.
Dim connetionString As String
Dim sqlCnn As SqlConnection
Dim sqlCmd As SqlCommand
Dim adapter As New SqlDataAdapter
Dim ds As New DataSet
Dim sql As String
connetionString = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Data_Ant.mdf;Integrated Security=True;Connect Timeout=30"
sql = "Select BN FROM DataTable"
adapter.TableMappings.Add("BN", sql)
If DataTable.RowCount > 0 Then
sqlCnn = New SqlConnection(connetionString)
Try
sqlCnn.Open()
sqlCmd = New SqlCommand(sql, sqlCnn)
adapter.SelectCommand = sqlCmd
adapter.Update(ds, "BN")
adapter.Dispose()
sqlCmd.Dispose()
sqlCnn.Close()
Catch ex As Exception
MsgBox("Can not open connection !" & vbCrLf & Err.Description)
End Try
ElseIf DataTable.RowCount = 0 Then
MsgBox("Empty data")
End If
End Sub
Please see more info below:
Data Table columns/format are structured for visual representation.
When User start the App Database can be empty/Can contain Values.
When users Runs certain function Closes App values are save and only values.
If I would you an MS Access I would structure same table/values and cross reference it with form values. Form Values come from outside source and Format/Qty is always known.
Hope this helps to have a cleaner look at my issue. Perhaps SQL is not a right choice for me? Does SQL needs to be build before value manipulation.
UPDATE: I Got rid of the Invalid Object error. Table had to be created 1st as I originally thought. However, My DataSet always comes up as EMPTY when I try to save... Cells do contain BN data as" 1,2, ....) Even if I to remove "If" logic Save and Load table comes out as empty. Something does load because when I try to ADD BN it tells me binding bla bla bla(different issue)
CODE:
Private Sub SaveData()
Dim connetionString As String = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Data_Ant.mdf;Integrated Security=True;Connect Timeout=30"
Dim sql As String = "SELECT BN FROM DataTable_d"
Dim sqlCnn As SqlConnection
Dim sqlCmd As SqlCommand
Dim adapter As New SqlDataAdapter
Dim ds As New DataSet()
adapter.TableMappings.Add("BN", sql)
If ds.Tables.Count > 0 Then
sqlCnn = New SqlConnection(connetionString)
Try
sqlCnn.Open()
sqlCmd = New SqlCommand(sql, sqlCnn)
adapter.SelectCommand = sqlCmd
adapter.Update(ds, "BN")
adapter.Dispose()
sqlCmd.Dispose()
sqlCnn.Close()
Catch ex As Exception
MsgBox("Can not open connection !" & vbCrLf & Err.Description)
End Try
ElseIf ds.Tables.Count = 0 Then
MsgBox("Empty data")
End If
End Sub
UPDATE: I got all the things working but I can't save multiple rows..... Could really use some help
In your SQL query remove WHERE DataTable ='. This statement is looking for a column name DataTable which I assume does not exist. The WHERE clause is used to help filter your query. You only use WHERE on column names in your table.
For instance:
SELECT BN FROM DataTable
will return all values from the BN column from DataTable.
Note that if you have multiple columns, the above query will still only return values from BN.
SELECT * FROM DataTable
will return every value in DataTable.
A helpful site to look at documentation for SQL is w3schools.
Let's start with just displaying some data. Add a DataGridView to a Form. You can call LoadData() from a button. I am not very sure of you connection string but give it a try.
Private dt As DataTable
Private sql As String = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Data_Ant.mdf;Integrated Security=True;Connect Timeout=30"
Private Sub LoadData()
'***EDIT*** Add instantiation line
dt = New DataTable()
'The Using...End Using blocks will close and dispose your database objects
'even if there is an error
Using cn As New SqlConnection(sql)
'You can pass the command text and the connection directly to the constructor
'In the select statement use the actual names of the field and table as they appear in the database.
Using cmd As New SqlCommand("Select BN From [Insert the name of the table in the database]", cn)
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
End Using
DataGridView1.DataSource = dt
End Sub
This is the simplest way I can think of to display data. We will proceed with changing the data once this works. If you get an error on cn.Open() We will have to work on the connection string.
****EDIT****
Private Sub TestConnection()
Dim sql As String = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Data_Ant.mdf;Integrated Security=True;Connect Timeout=30"
Using cn As New SqlConnection(sql)
cn.Open()
End Using
End Sub

SQL Server query parameter for copy data table to another table form ListView VB.net

I'm using VB.net 2013 and SQL Server Express. I want to copy data from the table that appears in the listview to the temporary table. But I got an error:
Operator '&' is not defined for types 'String' and 'System.Windows.Forms.ListViewItem.ListViewSubItem'
What are the correct parameters?
My code looks like this
For Each itm As ListViewItem In ListViewMasterBiaya.CheckedItems
Dim SIMPAN As String = "INSERT INTO TempEntriBiaya WHERE NoKode='" & ListViewMasterBiaya.SelectedItems(0).SubItems(0) & "'"
CMD = New SqlCommand(SIMPAN, CONN)
CMD.ExecuteNonQuery()
Next
End Sub
I also include the image as below, when I check it, the data will also copy to the temporary table
Comments and explanation in-line. Following LarsTech comments.
Dim SIMPAN As String = "INSERT INTO TempEntriBiaya (Column1Name, Column2Name) Values (#Column1, #Column2);"
'The Using...End Using blocks ensure that your ADO objects are closed and
'disposed event if there is an error
Using cn As New SqlConnection("Your connection string")
'The command and parameters only need to be declared once
'outside the loop, only the value of the parameters change
Using cmd As New SqlCommand(SIMPAN, cn)
cmd.Parameters.Add("#Column1", SqlDbType.Int)
cmd.Parameters.Add("#Column2", SqlDbType.VarChar)
'Open the connection at the last possible moment
cn.Open()
For Each itm As ListViewItem In ListViewMasterBiaya.CheckedItems
cmd.Parameters("#Column1").Value = itm.SubItems(0).Text
cmd.Parameters("#Column2").Value = itm.SubItems(1).Text
cmd.ExecuteNonQuery()
Next
End Using
End Using
EDIT Use event ListView.ItemChecked
Private Sub ListViewMasterBiaya_ItemChecked(sender As Object, e As ItemCheckedEventArgs) Handles ListViewMasterBiaya.ItemChecked
'e.Item returns the ListViewItem that changed its check
If e.Item.Checked = True Then
Dim SIMPAN As String = "INSERT INTO TempEntriBiaya (Column1Name, Column2Name) Values (#Column1, #Column2);"
'The Using...End Using blocks ensure that your ADO objects are closed and
'disposed event if there is an error
Using cn As New SqlConnection("Your connection string")
Using cmd As New SqlCommand(SIMPAN, cn)
cmd.Parameters.Add("#Column1", SqlDbType.Int).Value = e.Item.SubItems(0)
cmd.Parameters.Add("#Column2", SqlDbType.VarChar).Value = e.Item.SubItems(1)
'Open the connection at the last possible moment
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Using
End If
End Sub

Inserting contents of CSV file into database loses 1 record

I have an application that imports a CSV file (no header row) and writes the contents into a datatable. The datatable is then passed on as a parameter to a function in my DAL that uses the sqlBulkCopy command to write the data to a SQL Server database.
I have run tested the code as both a Webforms and Windows Forms environment and noticed that in both cases the first row of data is lost. Does anyone know why this should be the case and how I can rectify it? Thanks for any help.
I should add that this doesn't happen if the CSV file has a header row.
UI
Dim csvFileFolder As String = "D:\PROJECTS\Letters(DOTNET)\TextFiles\"
Dim csvFileName As String = "quad1a.txt"
Dim connString As String = "Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq=" _
& csvFileFolder & ";Extended Properties=""Text;HDR=No;FMT=Delimited"""
Dim conn As New Odbc.OdbcConnection(connString)
'Open a data adapter, specifying the file name to load
Dim da As New Odbc.OdbcDataAdapter("SELECT * FROM [" & csvFileName & "]", conn)
'Then fill a data table, which can be bound to a grid
Dim dt As New DataTable
da.Fill(dt)
grdQuad.DataSource = dt
grdQuad.DataBind()
LettersBLL.TemporaryPatientManager.InsertIntoBulkTable(dt)
DAL
Public Shared Function InsertIntoBulkTable(dt As DataTable) As DataTable
Using myConnection As New SqlConnection(ApplicationConfiguration.ConnectionString)
Using sqlBulkCopy As New SqlBulkCopy(myConnection)
'Set the database table name
sqlBulkCopy.DestinationTableName = "tblBulkInsert"
myConnection.Open()
sqlBulkCopy.WriteToServer(dt)
myConnection.Close()
End Using
End Using
Return Nothing
End Function
Try this...
Dim connString As String = "Driver={Microsoft Text Driver (*.txt; *.csv)};HDR=No;Dbq=" _& csvFileFolder & ";Extended Properties=""Text;HDR=No;FMT=Delimited"""
Added 'HDR=No' to your connection string
Or try specifying your sqlbulkcopy column mappings.
msdn.....
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.columnmappings.aspx
Example.....
http://www.codeproject.com/Articles/18418/Transferring-Data-Using-SqlBulkCopy

Removing items in an arraylist from another arraylist in VB.NET

I am writing a VB.NET webforms site, one page of which has to load a list of files into a listbox. It needs to load all PDF and TIF files in a directory that do not have entries in a database. I am doing this successfully at the moment with the following code. Basically, I query the database to get an arraylist of filename entries, then go through each file in the directory, check its name against each entry in the arraylist, and if its name is not in the arraylist, add it to list to bind to the listbox:
Dim category As String = "RFQ"
'Initialize database connection variables
Dim sql As String
Dim query As System.Data.SqlClient.SqlCommand
Dim result As System.Data.SqlClient.SqlDataReader
'Load document list from database
Dim savedfiles As New ArrayList
database.Open() 'Open connection to database
sql = "SELECT filename FROM fileheaders WHERE [category] = '" & category & "'" 'SQL query to read file header information
query = New System.Data.SqlClient.SqlCommand(sql, database) 'Create query to send to database
result = query.ExecuteReader() 'Execute query
While result.Read()
savedfiles.Add(row(result, "filename"))
End While
result.Close()
dbDocscan.Close()
'The following code section pulls all files from the current file directory.
Dim filelist = New ArrayList
Dim dir As New System.IO.DirectoryInfo(dirName) 'Get directory information
Dim files As System.IO.FileInfo() = dir.GetFiles() 'Get all files in directory
Dim file As System.IO.FileInfo
Dim i As Integer = 0
For Each file In files
If ((file.Extension Like ".pdf") Or (file.Extension Like ".tif")) And Not inArray(savedfiles, file.Name) Then
filelist.Add(file.Name) 'Add .pdf and .tif files to list of documents
End If
Next
filelist.TrimToSize()
eltFilelist.DataSource = filelist
eltFilelist.DataBind() 'Bind document list to listbox
Then the inArray function code:
Function inArray(arr As ArrayList, str As String) As Boolean
For Each item In arr
If TypeOf (item) Is String Then
If str = item Then
Return True
Exit Function
End If
End If
Next
Return False
End Function
Here's the problem: while it works, it seems terribly inefficient. There are around 27,000 files in the directory and around 26,000 file entries in the database. So I am checking each of 27,000 filenames against a list of 26,000 names. Without making this into a combinatorics problem, that's hundreds of millions of string matching statements. Is there a more efficient way to go about this?
You could use an SQL parameter to avoid problems with the category string (e.g. if it had an apostrophe in it a concatenated query string would be broken), get only the files in the directory which have the extensions you're interested in, and you could use LINQ to get the missing files in a simple way:
Imports System.Data.SqlClient
Imports System.IO
Module Module1
Function GetMissingFiles(sourceDirectory As String, category As String) As List(Of String)
Dim missingFiles As New List(Of String)
Dim filesInDatabase As New List(Of String)
' Query the database for the files in the given category'
Using conn As New SqlConnection("connection string here")
conn.Open()
Dim sqlCmd As String = "SELECT filename FROM fileheaders WHERE [category] = #category"
Dim query As New System.Data.SqlClient.SqlCommand(sqlCmd, conn)
'TODO: change .SqlDbType to what it is in the database.'
query.Parameters.Add(New SqlParameter With {.ParameterName = "#category", .SqlDbType = SqlDbType.NVarChar, .Value = category})
Dim rdr As SqlDataReader = query.ExecuteReader()
While rdr.Read()
filesInDatabase.Add(rdr.GetString(0))
End While
conn.Close()
End Using
'TODO: it could be that filesInDatabase.Count = 0 is valid. Adjust if required.'
If filesInDatabase.Count > 0 Then
' Get the existing files from the given directory.
' the extensions we are going to consider
Dim extensions() As String = {"pdf", "tif"}
Dim existingFiles As New List(Of String)
' get all the filenames (without the path) to consider'
For Each extn In extensions
existingFiles.AddRange(Directory.GetFiles(sourceDirectory, "*." & extn).ToList().Select(Function(p) Path.GetFileName(p)))
Next
missingFiles = existingFiles.Except(filesInDatabase).ToList()
End If
Return missingFiles
End Function
Sub Whatever()
Dim myMissingFiles As List(Of String)
Try
myMissingFiles = GetMissingFiles("C:\temp", "RFQ")
Catch ex As Exception
' Inform user it went wrong.'
End Try
If myMissingFiles IsNot Nothing AndAlso myMissingFiles.Count > 0 Then
eltFilelist.DataSource = myMissingFiles
eltFilelist.DataBind()
End If
End Sub
End Module
Instead of using an ArrayList, use a Dictionary or HashTable to save the file names from your query.
Your inArray function is doing a O(n) table scan for every file found, which is quite slow.
Both Dictionaries and HashTables has a Contains member that will search your file names at a significantly faster rate.

retrieving data in VB from SQL

I use Visual Basic 2010 and Microsoft SQL Server 2008. I have my database and my table and i made the connection (at least i think i did) in VB using only the interface.
What i want to know is how to get data from the database and use it into my VB project. I have of course searched for solutions already but the differences i find only confuse me more. What i need to know are the basics, the tools/objects and procedures to retrieve the data.
What i try to do at the moment is make a simple selection and put that data into a listbox right when the program starts, like this:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
SqlConnection1.Open()
SqlConnection1.Close()
End Sub
End Class
1) Create your connection string
Dim connectionString As String = "Data Source=localhost;........."
2) Connect to your Database
Dim connection As New SqlConnection(connectionString)
conn.Open()
3) Create a Command and the query
Dim command As New SqlCommand("SELECT * FROM Product", connection)
Dim reader As SqlDataReader = command.ExecuteReader() //Execute the Query
4) Retrieve your result. There are several ways
Dim dt As New DataTable()
dt.Load(reader)
'Close the connection
connection.Close()
5) Bind to your list box
myListBox.ItemSource = dt
Full code here
Using connection As New SqlConnection(connectionString)
Dim command As New SqlCommand("Select * from Products", connection)
command.Connection.Open()
SqlDataReader reader = command.ExecuteReader()
End Using
For more info
SQLCommand
SqlConnection1.Open()
using table As DataTable = New DataTable
using command as SqlCommand = New SqlCommand("SELECT blah blah", SqlConnection1)
using adapter As SqlDataAdapter = new SqlDataAdapter(command)
adapter.Fill(table)
end using
end using
for each row As DataRow in table.Rows
' add each listbox item
listbox1.Items.Add(row("column name"))
next
end using
SqlConnection1.Close()

Resources