VB Visual Basic 2026 中文教程
第 28 课 · 从“全部记录”到“我要的记录”

搜索、筛选与排序

真正的数据库应用不会每次都把所有记录全部显示出来。用户通常需要按姓名搜索、按课程筛选、找出达到某个成绩的学生,并按姓名或成绩排序。本课将把 WHERE、LIKE、AND、ORDER BY 与参数化 SQL 结合起来,建立一个可以灵活搜索和筛选 Students 表的界面。

环境:Visual Studio 2026 · VB.NET · .NET 10数据库:StudentManagementDB实作:StudentSearchFilter2026

本课学习目标

  • 使用 WHERE 限制查询结果。
  • 使用比较运算符筛选成绩。
  • 使用 LIKE 进行模糊文字搜索。
  • 理解 % 通配符。
  • 使用 AND 组合多个筛选条件。
  • 使用 ORDER BY 排序。
  • 理解 ASCDESC
  • 继续使用参数化 SQL 传入搜索条件。
  • 把筛选结果绑定到 DataGridView。
  • 设计“全部、搜索、筛选、排序”一体化界面。
  • 完成 StudentSearchFilter2026。

数据库中只有十几笔记录时,显示全部资料没有问题;但当记录增加到几百、几千甚至更多时,用户更需要精确查找。

搜索

按姓名查找

例如查找姓名包含“李”的学生。

筛选

只看某个课程

例如只显示 Visual Basic 2026 学生。

排序

把重要记录放前面

例如按照成绩由高到低显示。

28.2 WHERE 条件

最基本的筛选:

SELECT
    StudentID,
    Name,
    Course,
    Score
FROM dbo.Students
WHERE Score >= 80;

只会返回成绩至少 80 的记录。

WHERE Score = 80
成绩刚好等于 80。
WHERE Score > 80
成绩大于 80。
WHERE Score >= 80
成绩至少 80。
WHERE Score < 50
成绩低于 50。

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 & "%"
SQL 结构仍然固定 参数值可以包含 %,但不要因为使用 LIKE 就回到字符串拼接 SQL 的旧习惯。

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;
Name ASC Name DESC Score ASC Score DESC StudentID ASC

28.11 多字段排序

ORDER BY
    Course ASC,
    Score DESC;

意思是:

  1. 先按 Course 排序。
  2. 同一课程内,再按 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
不要把任意 TextBox 内容直接放到 ORDER BY 后面 排序列应该来自程序定义好的白名单选项,而不是让用户输入任意 SQL 片段。

28.13 实作:Student Search & Filter 2026

建立新的 Windows Forms 项目:

StudentSearchFilter2026

继续使用:

StudentManagementDB
DatabaseHelper.vb
Microsoft.Data.SqlClient
DataGridView
Student Search & Filter 2026
姓名关键字:
课程:
Visual Basic 2026
最低成绩:
80
排序:
成绩高到低
搜索 应用筛选 显示全部 清除条件
Student ID姓名课程成绩
7李华Visual Basic 202693.00
1李明Visual Basic 202688.00

28.14 新增搜索控件

控件Name用途
TextBoxtxtSearchName输入姓名关键字。
ComboBoxcmbCourse选择课程。
TextBoxtxtMinScore输入最低成绩。
ComboBoxcmbSort选择排序方式。
ButtonbtnSearch按姓名搜索。
ButtonbtnApplyFilter应用课程、成绩与排序。
ButtonbtnShowAll恢复全部记录。
ButtonbtnClearFilters清除筛选条件。

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 条件”。

WHERE 1 = 1 是动态查询构建技巧 它不是必须的 SQL 语法,而是让多个可选筛选条件更容易组合。

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 本课完整数据流

1
用户输入条件

姓名关键字、课程、最低成绩、排序方式。

2
验证条件

特别检查最低成绩是否为有效数字。

3
建立 SQL + 参数

WHERE 与 LIKE 使用参数化值。

4
SqlDataAdapter.Fill

把筛选结果填入 DataTable。

5
绑定 DataGridView

只显示符合条件的记录。

28.24 初学者常见错误

错误 1

LIKE 忘记 %

LIKE @NamePattern 本身不会自动变成模糊搜索;参数值需要包含通配符。

错误 2

把用户输入直接放到 ORDER BY

排序列不是普通参数值,应从程序定义好的选项中选择。

错误 3

筛选条件为空仍强行加入参数

可选条件为空时,应该不加入对应 SQL 条件。

错误 4

筛选后忘记显示记录数

用户应该知道当前 DataGridView 是全部记录还是筛选后的子集。

28.25 小练习

  1. 新增“姓名以某字开头”的搜索,参数值使用 keyword & "%"
  2. 新增最高成绩筛选:Score <= @MaxScore
  3. 同时支持最低成绩与最高成绩,形成成绩区间。
  4. 加入“课程 + 姓名关键字”的组合搜索。
  5. 新增“课程升序、成绩降序”的排序方式。
  6. 在 lblStatus 显示当前筛选条件摘要。
  7. 把课程 ComboBox 改成从数据库读取 DISTINCT Course。

本课复习

  1. WHERE 的主要作用是什么?
  2. LIKE 与等号查询有什么不同?
  3. % 在 LIKE 中代表什么?
  4. 怎样参数化最低成绩筛选?
  5. AND 用来做什么?
  6. ORDER BY Score DESC 表示什么?
  7. 为什么排序字段不能直接使用普通 SqlParameter?
  8. WHERE 1 = 1 为什么适合动态筛选?
  9. Decimal? 为什么适合表示“可选最低成绩”?
  10. 筛选后为什么应该更新 DataGridView 和状态文字?