本课学习目标
- 使用 WHERE 限制查询结果。
- 使用比较运算符筛选成绩。
- 使用 LIKE 进行模糊文字搜索。
- 理解 % 通配符。
- 使用 AND 组合多个筛选条件。
- 使用 ORDER BY 排序。
- 理解 ASC 与 DESC。
- 继续使用参数化 SQL 传入搜索条件。
- 把筛选结果绑定到 DataGridView。
- 设计“全部、搜索、筛选、排序”一体化界面。
- 完成 StudentSearchFilter2026。
28.1 为什么需要搜索与筛选?
数据库中只有十几笔记录时,显示全部资料没有问题;但当记录增加到几百、几千甚至更多时,用户更需要精确查找。
按姓名查找
例如查找姓名包含“李”的学生。
只看某个课程
例如只显示 Visual Basic 2026 学生。
把重要记录放前面
例如按照成绩由高到低显示。
28.2 WHERE 条件
最基本的筛选:
SELECT
StudentID,
Name,
Course,
Score
FROM dbo.Students
WHERE Score >= 80;
只会返回成绩至少 80 的记录。
28.3 成绩筛选也要参数化
不要写:
"WHERE Score >= " & txtMinScore.Text
而是:
WHERE Score >= @MinScore
然后建立参数:
Dim scoreParameter As SqlParameter =
command.Parameters.Add(
"@MinScore",
SqlDbType.Decimal)
scoreParameter.Precision = 5
scoreParameter.Scale = 2
scoreParameter.Value = minScore
28.4 LIKE 模糊搜索
如果使用:
WHERE Name = @Name
数据库只会寻找完全相同的姓名。
如果希望用户只输入部分姓名,例如:
李
也能找到:
李明
李华
李小文
可以使用:
WHERE Name LIKE @NamePattern
28.5 % 通配符
VB.NET 中通常把通配符放入参数值:
command.Parameters.Add(
"@NamePattern",
SqlDbType.NVarChar,
100).Value =
"%" & keyword & "%"
28.6 按姓名模糊搜索
Private Function SearchStudentsByName(
keyword As String) As DataTable
Const sql As String =
"SELECT StudentID, Name, Course, Score " &
"FROM dbo.Students " &
"WHERE Name LIKE @NamePattern " &
"ORDER BY StudentID;"
Using connection As New SqlConnection(
DatabaseHelper.ConnectionString)
Using command As New SqlCommand(
sql,
connection)
command.Parameters.Add(
"@NamePattern",
SqlDbType.NVarChar,
100).Value =
"%" & keyword & "%"
Using adapter As New SqlDataAdapter(
command)
Dim table As New DataTable()
adapter.Fill(table)
Return table
End Using
End Using
End Using
End Function
28.7 按课程筛选
Private Function FilterStudentsByCourse(
course As String) As DataTable
Const sql As String =
"SELECT StudentID, Name, Course, Score " &
"FROM dbo.Students " &
"WHERE Course = @Course " &
"ORDER BY Name;"
Using connection As New SqlConnection(
DatabaseHelper.ConnectionString)
Using command As New SqlCommand(
sql,
connection)
command.Parameters.Add(
"@Course",
SqlDbType.NVarChar,
100).Value =
course
Using adapter As New SqlDataAdapter(
command)
Dim table As New DataTable()
adapter.Fill(table)
Return table
End Using
End Using
End Using
End Function
28.8 按最低成绩筛选
Private Function FilterByMinimumScore(
minScore As Decimal) As DataTable
Const sql As String =
"SELECT StudentID, Name, Course, Score " &
"FROM dbo.Students " &
"WHERE Score >= @MinScore " &
"ORDER BY Score DESC;"
Using connection As New SqlConnection(
DatabaseHelper.ConnectionString)
Using command As New SqlCommand(
sql,
connection)
Dim scoreParameter As SqlParameter =
command.Parameters.Add(
"@MinScore",
SqlDbType.Decimal)
scoreParameter.Precision = 5
scoreParameter.Scale = 2
scoreParameter.Value = minScore
Using adapter As New SqlDataAdapter(
command)
Dim table As New DataTable()
adapter.Fill(table)
Return table
End Using
End Using
End Using
End Function
28.9 使用 AND 组合条件
例如:只看某课程中成绩至少 80 的学生:
SELECT
StudentID,
Name,
Course,
Score
FROM dbo.Students
WHERE Course = @Course
AND Score >= @MinScore;
两个参数:
command.Parameters.Add(
"@Course",
SqlDbType.NVarChar,
100).Value =
course
Dim scoreParameter As SqlParameter =
command.Parameters.Add(
"@MinScore",
SqlDbType.Decimal)
scoreParameter.Precision = 5
scoreParameter.Scale = 2
scoreParameter.Value = minScore
28.10 ORDER BY 排序
默认升序:
ORDER BY Name ASC;
降序:
ORDER BY Score DESC;
28.11 多字段排序
ORDER BY
Course ASC,
Score DESC;
意思是:
- 先按 Course 排序。
- 同一课程内,再按 Score 从高到低排序。
28.12 排序字段不要直接来自用户输入
SQL 参数适合传“数据值”,但不能简单用参数代表列名:
ORDER BY @ColumnName
这并不会像很多初学者想象的那样把参数当成列名。
如果界面允许用户选择排序方式,应该由程序把有限的选项映射到预先允许的 SQL 片段。
Private Function GetOrderByClause(
sortOption As String) As String
Select Case sortOption
Case "姓名 A-Z"
Return "Name ASC"
Case "成绩高到低"
Return "Score DESC"
Case "成绩低到高"
Return "Score ASC"
Case Else
Return "StudentID ASC"
End Select
End Function
28.13 实作:Student Search & Filter 2026
建立新的 Windows Forms 项目:
StudentSearchFilter2026
继续使用:
StudentManagementDB
DatabaseHelper.vb
Microsoft.Data.SqlClient
DataGridView
| Student ID | 姓名 | 课程 | 成绩 |
|---|---|---|---|
| 7 | 李华 | Visual Basic 2026 | 93.00 |
| 1 | 李明 | Visual Basic 2026 | 88.00 |
28.14 新增搜索控件
| 控件 | Name | 用途 |
|---|---|---|
| TextBox | txtSearchName | 输入姓名关键字。 |
| ComboBox | cmbCourse | 选择课程。 |
| TextBox | txtMinScore | 输入最低成绩。 |
| ComboBox | cmbSort | 选择排序方式。 |
| Button | btnSearch | 按姓名搜索。 |
| Button | btnApplyFilter | 应用课程、成绩与排序。 |
| Button | btnShowAll | 恢复全部记录。 |
| Button | btnClearFilters | 清除筛选条件。 |
28.15 Form.Load 准备 ComboBox
Private Sub Form1_Load(
sender As Object,
e As EventArgs) Handles MyBase.Load
cmbCourse.Items.Clear()
cmbCourse.Items.Add("全部课程")
cmbCourse.Items.Add("Visual Basic 2026")
cmbCourse.Items.Add("C# Programming")
cmbCourse.Items.Add("Python Programming")
cmbCourse.SelectedIndex = 0
cmbSort.Items.Clear()
cmbSort.Items.Add("Student ID")
cmbSort.Items.Add("姓名 A-Z")
cmbSort.Items.Add("成绩高到低")
cmbSort.Items.Add("成绩低到高")
cmbSort.SelectedIndex = 0
LoadAllStudents()
End Sub
28.16 姓名搜索按钮
Private Sub btnSearch_Click(
sender As Object,
e As EventArgs) Handles btnSearch.Click
Dim keyword As String =
txtSearchName.Text.Trim()
If String.IsNullOrWhiteSpace(
keyword) Then
LoadAllStudents()
Exit Sub
End If
Try
Dim table As DataTable =
SearchStudentsByName(
keyword)
dgvStudents.DataSource =
table
lblStatus.Text =
$"找到 {table.Rows.Count} 笔记录。"
Catch ex As SqlException
MessageBox.Show(
ex.Message,
"数据库错误",
MessageBoxButtons.OK,
MessageBoxIcon.Error)
End Try
End Sub
28.17 综合筛选方法
为了让一个按钮同时处理“课程 + 最低成绩 + 排序”,可以建立:
Private Function FilterStudents(
course As String,
minScore As Decimal?,
orderByClause As String) As DataTable
Dim sql As String =
"SELECT StudentID, Name, Course, Score " &
"FROM dbo.Students " &
"WHERE 1 = 1 "
Using connection As New SqlConnection(
DatabaseHelper.ConnectionString)
Using command As New SqlCommand()
command.Connection =
connection
If course <>
"全部课程" Then
sql &=
"AND Course = @Course "
command.Parameters.Add(
"@Course",
SqlDbType.NVarChar,
100).Value =
course
End If
If minScore.HasValue Then
sql &=
"AND Score >= @MinScore "
Dim parameter As SqlParameter =
command.Parameters.Add(
"@MinScore",
SqlDbType.Decimal)
parameter.Precision = 5
parameter.Scale = 2
parameter.Value =
minScore.Value
End If
sql &=
"ORDER BY " &
orderByClause &
";"
command.CommandText =
sql
Using adapter As New SqlDataAdapter(
command)
Dim table As New DataTable()
adapter.Fill(table)
Return table
End Using
End Using
End Using
End Function
28.18 为什么使用 WHERE 1 = 1?
WHERE 1 = 1
这个条件永远为 True。它的主要用途是让后面动态追加条件时可以统一写:
AND Course = @Course
AND Score >= @MinScore
这样就不需要判断“这是第一个 WHERE 条件还是后续 AND 条件”。
28.19 Nullable(Of Decimal) 表示可选最低成绩
参数:
minScore As Decimal?
等同于:
Nullable(Of Decimal)
它可以:
有一个 Decimal 值
也可以:
Nothing
因此用户没有输入最低成绩时,就可以不加入 Score 条件。
28.20 应用筛选按钮
Private Sub btnApplyFilter_Click(
sender As Object,
e As EventArgs) Handles btnApplyFilter.Click
Dim minScore As Decimal?
Dim scoreValue As Decimal
If String.IsNullOrWhiteSpace(
txtMinScore.Text) Then
minScore =
Nothing
ElseIf Decimal.TryParse(
txtMinScore.Text,
scoreValue) Then
If scoreValue < 0D OrElse
scoreValue > 100D Then
MessageBox.Show(
"最低成绩必须介于 0 与 100。")
Exit Sub
End If
minScore =
scoreValue
Else
MessageBox.Show(
"请输入有效最低成绩。")
Exit Sub
End If
Dim orderByClause As String =
GetOrderByClause(
cmbSort.Text)
Try
Dim table As DataTable =
FilterStudents(
cmbCourse.Text,
minScore,
orderByClause)
dgvStudents.DataSource =
table
lblStatus.Text =
$"筛选结果:{table.Rows.Count} 笔记录。"
Catch ex As SqlException
MessageBox.Show(
ex.Message,
"数据库错误",
MessageBoxButtons.OK,
MessageBoxIcon.Error)
End Try
End Sub
28.21 显示全部与清除条件
Private Sub btnShowAll_Click(
sender As Object,
e As EventArgs) Handles btnShowAll.Click
LoadAllStudents()
End Sub
清除:
Private Sub btnClearFilters_Click(
sender As Object,
e As EventArgs) Handles btnClearFilters.Click
txtSearchName.Clear()
txtMinScore.Clear()
cmbCourse.SelectedIndex = 0
cmbSort.SelectedIndex = 0
LoadAllStudents()
txtSearchName.Focus()
End Sub
28.22 LoadAllStudents
Private Sub LoadAllStudents()
Const sql As String =
"SELECT StudentID, Name, Course, Score " &
"FROM dbo.Students " &
"ORDER BY StudentID;"
Using connection As New SqlConnection(
DatabaseHelper.ConnectionString)
Using adapter As New SqlDataAdapter(
sql,
connection)
Dim table As New DataTable()
adapter.Fill(table)
dgvStudents.DataSource =
table
lblStatus.Text =
$"显示全部 {table.Rows.Count} 笔记录。"
End Using
End Using
End Sub
28.23 本课完整数据流
姓名关键字、课程、最低成绩、排序方式。
特别检查最低成绩是否为有效数字。
WHERE 与 LIKE 使用参数化值。
把筛选结果填入 DataTable。
只显示符合条件的记录。
28.24 初学者常见错误
LIKE 忘记 %
LIKE @NamePattern 本身不会自动变成模糊搜索;参数值需要包含通配符。
把用户输入直接放到 ORDER BY
排序列不是普通参数值,应从程序定义好的选项中选择。
筛选条件为空仍强行加入参数
可选条件为空时,应该不加入对应 SQL 条件。
筛选后忘记显示记录数
用户应该知道当前 DataGridView 是全部记录还是筛选后的子集。
28.25 小练习
- 新增“姓名以某字开头”的搜索,参数值使用 keyword & "%"。
- 新增最高成绩筛选:Score <= @MaxScore。
- 同时支持最低成绩与最高成绩,形成成绩区间。
- 加入“课程 + 姓名关键字”的组合搜索。
- 新增“课程升序、成绩降序”的排序方式。
- 在 lblStatus 显示当前筛选条件摘要。
- 把课程 ComboBox 改成从数据库读取 DISTINCT Course。
本课复习
- WHERE 的主要作用是什么?
- LIKE 与等号查询有什么不同?
- % 在 LIKE 中代表什么?
- 怎样参数化最低成绩筛选?
- AND 用来做什么?
- ORDER BY Score DESC 表示什么?
- 为什么排序字段不能直接使用普通 SqlParameter?
- WHERE 1 = 1 为什么适合动态筛选?
- Decimal? 为什么适合表示“可选最低成绩”?
- 筛选后为什么应该更新 DataGridView 和状态文字?