Database Introduction
Connect VB 2026 to a real database using ADO.NET — understand the architecture, write your first SQL queries, load data into a DataGridView, and build a complete read/search application with SQLite or Microsoft Access.
SELECT statement, fill a DataTable via a DataAdapter, and bind it to a DataGridView with one line: dgv.DataSource = dt. Always open the connection inside a Using block so it is closed and disposed even if an exception occurs. For school projects and simple apps, SQLite (zero installation, single file) is the easiest choice; Microsoft Access (.accdb) works well if students already have Office.
29.1 ADO.NET Architecture
ADO.NET uses a layered architecture: a Connection object opens the database, a Command object carries the SQL statement, a DataAdapter executes the query and fills an in-memory DataTable, and the DataTable is bound directly to the UI (DataGridView, ComboBox, etc.).
DataSource = dt
In-memory cache
Fill(dt) / Update(dt)
SQL string
Open / Close
SQLite / Access / SQL Server
Choosing a Database for VB 2026 Projects
| Database | Connection type | Best for | Notes |
|---|---|---|---|
| SQLite (.db file) | SQLiteConnection (NuGet) | School / portable apps | Zero install, single file, .NET provider via System.Data.SQLite or Microsoft.Data.Sqlite |
| Microsoft Access (.accdb) | OleDbConnection | Office-integrated projects | Built-in OleDb provider, 64-bit requires ACE driver |
| SQL Server LocalDB | SqlConnection | Real-world production apps | Installed with Visual Studio; full T-SQL, stored procs |
| SQL Server Express | SqlConnection | Team / networked projects | Free edition, up to 10 GB, network capable |
29.2 SQL Primer — SELECT, WHERE, ORDER BY
SQL (Structured Query Language) is the language used to read and modify database tables. You only need five statements to build most VB applications: SELECT, INSERT, UPDATE, DELETE, and CREATE TABLE.
-- Read all columns from Students table SELECT * FROM Students; -- Read specific columns, filtered and sorted SELECT StudentID, Name, Grade FROM Students WHERE Grade >= 70 ORDER BY Name ASC; -- Pattern search with LIKE (% = wildcard) SELECT * FROM Students WHERE Name LIKE 'A%'; -- Aggregate: count, average, max SELECT COUNT(*), AVG(Grade), MAX(Grade) FROM Students; -- Insert a new row INSERT INTO Students (Name, Grade, Class) VALUES ('Alice Wong', 88, '4A'); -- Update an existing row UPDATE Students SET Grade = 92 WHERE StudentID = 5; -- Delete a row DELETE FROM Students WHERE StudentID = 5; -- Create a table CREATE TABLE IF NOT EXISTS Students ( StudentID INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT NOT NULL, Grade REAL DEFAULT 0, Class TEXT );
An in-browser SQL sandbox with a pre-loaded Students table. Type or choose a query, click Execute, and see results instantly. Shows the equivalent VB ADO.NET code for each query.
29.3 Connecting to SQLite in VB 2026
SQLite is the recommended beginner database — a single .db file, no server required. Add the NuGet package Microsoft.Data.Sqlite (or System.Data.SQLite), then use SqliteConnection.
In Visual Studio 2026: right-click project → Manage NuGet Packages → search Microsoft.Data.Sqlite → Install. Then add Imports Microsoft.Data.Sqlite at the top of your form file. The database file is created automatically the first time you open the connection.
Imports Microsoft.Data.Sqlite ' NuGet: Microsoft.Data.Sqlite ' Connection string — database file in same folder as the exe Private Const CONN_STR = "Data Source=students.db" ' --- Create the table if it doesn't exist yet --- Private Sub CreateTable() Using conn As New SqliteConnection(CONN_STR) conn.Open() Using cmd As New SqliteCommand( "CREATE TABLE IF NOT EXISTS Students (" & " StudentID INTEGER PRIMARY KEY AUTOINCREMENT," & " Name TEXT NOT NULL," & " Grade REAL DEFAULT 0," & " Class TEXT" & ")", conn) cmd.ExecuteNonQuery() End Using End Using End Sub ' --- Load all students into DataGridView --- Private Sub LoadStudents() Dim dt As New DataTable() Using conn As New SqliteConnection(CONN_STR) conn.Open() Using da As New SqliteDataAdapter("SELECT * FROM Students ORDER BY Name", conn) da.Fill(dt) End Using End Using dgvStudents.DataSource = dt ' auto-generates columns lblCount.Text = $"{dt.Rows.Count} records" End Sub ' --- Search by name --- Private Sub SearchStudents(nameFilter As String) Dim dt As New DataTable() Using conn As New SqliteConnection(CONN_STR) conn.Open() Dim sql = "SELECT * FROM Students WHERE Name LIKE @Filter ORDER BY Name" Using da As New SqliteDataAdapter(sql, conn) da.SelectCommand.Parameters.AddWithValue("@Filter", $"%{nameFilter}%") da.Fill(dt) End Using End Using dgvStudents.DataSource = dt End Sub ' --- Form_Load: create table, load data --- Private Sub Form_Load(...) Handles MyBase.Load CreateTable() LoadStudents() End Sub
Writing "SELECT * FROM Students WHERE Name = '" & txtName.Text & "'" is a SQL injection vulnerability. A user could type ' OR '1'='1 to retrieve all records, or worse. Always use parameterised queries: cmd.Parameters.AddWithValue("@Name", txtName.Text). The @Name placeholder is replaced safely — special characters are never interpreted as SQL.
29.4 Connecting to Microsoft Access (.accdb)
If your school uses Microsoft Office, connecting to an Access database file requires the OleDb provider. Note that on 64-bit Windows you must install the Microsoft Access Database Engine 2016 Redistributable (free from Microsoft) and compile your project as x86.
Imports System.Data.OleDb ' Connection string for .accdb (Access 2007–2016 format) Private connStr As String = "Provider=Microsoft.ACE.OLEDB.12.0;" & "Data Source=C:\School\students.accdb" ' --- Load all records into DataGridView --- Private Sub LoadData() Dim dt As New DataTable() Using conn As New OleDbConnection(connStr) conn.Open() Using da As New OleDbDataAdapter("SELECT * FROM Students", conn) da.Fill(dt) End Using End Using DataGridView1.DataSource = dt End Sub ' --- Parameterised INSERT (OleDb uses ? placeholders, not @name) --- Private Sub InsertStudent(name As String, grade As Double, cls As String) Using conn As New OleDbConnection(connStr) conn.Open() Dim sql = "INSERT INTO Students (Name, Grade, Class) VALUES (?, ?, ?)" Using cmd As New OleDbCommand(sql, conn) cmd.Parameters.AddWithValue("@Name", name) cmd.Parameters.AddWithValue("@Grade", grade) cmd.Parameters.AddWithValue("@Class", cls) cmd.ExecuteNonQuery() End Using End Using LoadData() ' refresh the grid End Sub ' --- Get a single scalar value --- Private Function GetStudentCount() As Integer Using conn As New OleDbConnection(connStr) conn.Open() Using cmd As New OleDbCommand("SELECT COUNT(*) FROM Students", conn) Return CInt(cmd.ExecuteScalar()) End Using End Using End Function
Simulates loading a DataTable from a database query and binding it to a DataGridView. Shows how da.Fill(dt) → dgv.DataSource = dt populates the grid, and how filtering with WHERE narrows results.
29.5 Reading Rows with ExecuteReader
For large result sets where you only need to read through rows once (not bind to a grid), use a DataReader — it is faster and uses less memory than filling a DataTable, because it fetches one row at a time without loading everything into RAM.
' --- DataReader: fast forward-only read --- Private Sub ListTopStudents() Using conn As New SqliteConnection(CONN_STR) conn.Open() Dim sql = "SELECT Name, Grade FROM Students WHERE Grade >= @Min ORDER BY Grade DESC" Using cmd As New SqliteCommand(sql, conn) cmd.Parameters.AddWithValue("@Min", 80) Using reader = cmd.ExecuteReader() lstResults.Items.Clear() While reader.Read() Dim name = reader.GetString(0) ' column 0 = Name Dim grade = reader.GetDouble(1) ' column 1 = Grade lstResults.Items.Add($"{name}: {grade}") End While End Using End Using End Using End Sub ' --- Column access alternatives --- reader.GetString(0) ' by index (fast) reader("Name").ToString() ' by column name (convenient) reader.IsDBNull(2) ' check for NULL before reading ' --- ExecuteScalar: single value --- Dim avg = CDbl(cmd.ExecuteScalar()) ' returns first column of first row ' --- ExecuteNonQuery: INSERT / UPDATE / DELETE --- Dim rowsAffected = cmd.ExecuteNonQuery() ' returns count of rows changed
Step through the ADO.NET pipeline manually: open connection, run command, read rows one by one. The console shows each step, like an actual database session.
29.6 INSERT, UPDATE, and DELETE
Data modification uses the same pattern as reading, but calls ExecuteNonQuery() instead of Fill(). Always use @parameter placeholders (SQLite / SQL Server) or ? (OleDb/Access) — never string-concatenate user input.
' --- INSERT --- Private Sub AddStudent(name As String, grade As Double, cls As String) Using conn As New SqliteConnection(CONN_STR) conn.Open() Dim sql = "INSERT INTO Students (Name, Grade, Class) VALUES (@Name, @Grade, @Class)" Using cmd As New SqliteCommand(sql, conn) cmd.Parameters.AddWithValue("@Name", name) cmd.Parameters.AddWithValue("@Grade", grade) cmd.Parameters.AddWithValue("@Class", cls) cmd.ExecuteNonQuery() End Using End Using LoadStudents() ' refresh DataGridView End Sub ' --- UPDATE --- Private Sub UpdateGrade(studentId As Integer, newGrade As Double) Using conn As New SqliteConnection(CONN_STR) conn.Open() Dim sql = "UPDATE Students SET Grade = @Grade WHERE StudentID = @ID" Using cmd As New SqliteCommand(sql, conn) cmd.Parameters.AddWithValue("@Grade", newGrade) cmd.Parameters.AddWithValue("@ID", studentId) Dim rows = cmd.ExecuteNonQuery() MessageBox.Show($"{rows} row(s) updated.") End Using End Using LoadStudents() End Sub ' --- DELETE --- Private Sub DeleteStudent(studentId As Integer) If MessageBox.Show("Delete this student?", "Confirm", MessageBoxButtons.YesNo) <> DialogResult.Yes Then Return Using conn As New SqliteConnection(CONN_STR) conn.Open() Using cmd As New SqliteCommand("DELETE FROM Students WHERE StudentID = @ID", conn) cmd.Parameters.AddWithValue("@ID", studentId) cmd.ExecuteNonQuery() End Using End Using LoadStudents() End Sub ' --- Read selected row from DataGridView --- Private Sub dgvStudents_CellClick(...) Handles dgvStudents.CellClick If dgvStudents.SelectedRows.Count = 0 Then Return Dim row = dgvStudents.SelectedRows(0) Dim id = CInt(row.Cells("StudentID").Value) Dim name = row.Cells("Name").Value.ToString() Dim grade = CDbl(row.Cells("Grade").Value) txtName.Text = name nudGrade.Value = grade _selectedId = id ' store for UPDATE/DELETE End Sub
A complete student record manager — Add, Edit, Delete, and Search. Click a row to populate the form fields for editing. Shows the exact VB ADO.NET code for every operation.
| ID | Name | Grade | Class |
|---|
29.7 GitHub Copilot — Auto-complete Connection Setup
' Set up a SQLite database for a library app: Books table with BookID, Title, Author, Year, Available (boolean). Load into DataGridView, support search by title, mark a book as borrowed (Available = False).'' Library app — Books table with borrow tracking. Imports Microsoft.Data.Sqlite Private Const DB = "Data Source=library.db" Private _selectedBookId As Integer = -1 Private Sub EnsureSchema() Using conn As New SqliteConnection(DB) conn.Open() Using cmd As New SqliteCommand( "CREATE TABLE IF NOT EXISTS Books (" & " BookID INTEGER PRIMARY KEY AUTOINCREMENT," & " Title TEXT NOT NULL," & " Author TEXT," & " Year INTEGER," & " Available INTEGER DEFAULT 1)", conn) ' 1=Yes, 0=No cmd.ExecuteNonQuery() End Using End Using End Sub Private Sub LoadBooks(Optional filter As String = "") Dim dt As New DataTable() Dim sql = "SELECT BookID, Title, Author, Year," & " CASE Available WHEN 1 THEN 'Yes' ELSE 'Borrowed' END AS Available" & " FROM Books WHERE Title LIKE @F ORDER BY Title" Using conn As New SqliteConnection(DB) conn.Open() Using da As New SqliteDataAdapter(sql, conn) da.SelectCommand.Parameters.AddWithValue("@F", $"%{filter}%") da.Fill(dt) End Using End Using dgvBooks.DataSource = dt lblCount.Text = $"{dt.Rows.Count} books" End Sub Private Sub BorrowBook() If _selectedBookId < 0 Then Return Using conn As New SqliteConnection(DB) conn.Open() Using cmd As New SqliteCommand( "UPDATE Books SET Available = 0 WHERE BookID = @ID AND Available = 1", conn) cmd.Parameters.AddWithValue("@ID", _selectedBookId) Dim rows = cmd.ExecuteNonQuery() If rows = 0 Then MessageBox.Show("Book already borrowed.") End Using End Using LoadBooks(txtSearch.Text) End Sub Private Sub dgvBooks_CellClick(...) Handles dgvBooks.CellClick If dgvBooks.SelectedRows.Count > 0 Then _selectedBookId = CInt(dgvBooks.SelectedRows(0).Cells("BookID").Value) End If End Sub Private Sub txtSearch_TextChanged(...) Handles txtSearch.TextChanged LoadBooks(txtSearch.Text) ' live search as user types End Sub
Try these in the Copilot Chat panel:
- "Write a helper function that returns a DataTable from any SELECT query — takes the SQL string and a Dictionary of parameter names/values, returns a populated DataTable"
- "Generate INSERT statements to seed the Students table with 10 sample rows: realistic Malaysian student names, grades between 55 and 98, classes 4A through 5B"
- "Add error handling to the LoadStudents Sub: wrap in Try-Catch, show a MessageBox with the SQLite error message, and log the exception to a text file"
- "Write a backup function that copies the SQLite .db file to a timestamped filename in an /backups subfolder each time the application closes"
Lesson Summary
- ADO.NET follows a layered pattern: Connection → Command → DataAdapter → DataTable → DataGridView. Fill the DataTable offline, then bind it with
dgv.DataSource = dt. - Always wrap connections in
Usingblocks — they guarantee the connection is closed and disposed even if an exception is thrown. - SQLite (zero install, single
.dbfile) is the easiest choice for school projects. Add theMicrosoft.Data.SqliteNuGet package and useSqliteConnection. - For Microsoft Access (
.accdb) useOleDbConnectionwith the ACE provider. OleDb uses?positional placeholders, not@namenamed parameters. - Never concatenate user input into SQL strings — use
cmd.Parameters.AddWithValue("@Name", value)for every value that comes from a user control. - Use
da.Fill(dt)+dgv.DataSource = dtto bind a query result to a grid. Usecmd.ExecuteNonQuery()for INSERT/UPDATE/DELETE. Usecmd.ExecuteScalar()for a single aggregate value (COUNT, AVG, MAX). - A DataReader (
cmd.ExecuteReader()) reads rows one at a time — faster and more memory-efficient for large result sets you only need to scan once.
Exercises
Exercise 29.1 — Student Grade Viewer
- Create a SQLite database
school.dbwith aStudentstable (StudentID, Name, Grade, Class). - Seed it with 10 rows using INSERT statements. On
Form_Load, callCreateTable()thenLoadStudents()to populate a DataGridView. - Add a TextBox for name search and a NumericUpDown for minimum grade — filter on button click using parameterised
WHERE Name LIKE @F AND Grade >= @Min. - Show a label: "X records found" after each load.
- Copilot challenge: "Add a bar chart below the DataGridView that shows the grade distribution in 10-point buckets (0–9, 10–19, … 90–100) drawn with GDI+"
Exercise 29.2 — Contact Book
- Database:
contacts.db— Contacts table (ContactID, FullName, Phone, Email, Group: Friend/Work/Family). - DataGridView showing all contacts. Form fields (TextBox + ComboBox for Group) to Add, Update, and Delete.
- Clicking a row fills the form for editing. Confirm delete with a MessageBox.
- A ComboBox to filter by Group (show only "Work" contacts, etc.).
- Copilot challenge: "Export the current DataGridView content to a CSV file: iterate dgv.Rows, build comma-separated strings, write to a .csv with StreamWriter"
Exercise 29.3 — Inventory Tracker
- Database:
inventory.db— Products table (ProductID, Name, Category, Quantity, Price). - DataGridView with search by Name and filter by Category (ComboBox auto-populated from
SELECT DISTINCT Category). - Show total inventory value (
SUM(Quantity * Price)) in a label usingExecuteScalar(). - Highlight rows where Quantity < 5 in red using
dgv.RowPrePaintevent. - Copilot challenge: "Add a ReOrder button that generates a text report of all items with Quantity < 5, formatted as a purchase order with today's date, and saves it to reorder.txt"
Related Resources
← Lesson 28
Animation — Timer & GDI+.
Lesson 30 →
Connecting DB — BindingSource, live editing.
MS Docs — ADO.NET
Complete ADO.NET reference and tutorials.
SQLite Data Types
SQLite type affinity system explained.
Featured Books
Visual Basic 2022 Made Easy
Database chapters covering ADO.NET, DataGridView, and CRUD with Access and SQL Server.
View on Amazon →
VB Programming With Code Examples
Worked database programs: student records, inventory, and contact management.
View on Amazon →