SQL:自定义记录集的 SQL 语句 (ODBC)

本主题介绍:

  • 框架如何构造 SQL 语句

  • 如何重写 SQL 语句

注意

此信息适用于 MFC ODBC 类。 如果使用的是 MFC DAO 类,请参阅 DAO 帮助中的主题“Microsoft Jet 数据库引擎 SQL 和 ANSI SQL 的比较”。

SQL 语句构造

记录集的记录选择主要基于 SQL SELECT 语句。 使用向导声明类时,它会写入一个重写版本的 GetDefaultSQL 成员函数,其外观如下所示(针对名为 CAuthors 的记录集类)。

CString CAuthors::GetDefaultSQL()
{
    return "AUTHORS";
}

默认情况下,此重写返回使用向导指定的表名称。 在此示例中,表名称为“AUTHORS”。稍后调用记录集的 Open 成员函数时,Open 会构造最终的 SELECT 语句,其格式如下:

SELECT rfx-field-list FROM table-name [WHERE m_strFilter]
       [ORDER BY m_strSort]

其中,通过调用 GetDefaultSQL 获取 table-name,并从 DoFieldExchange 中的 RFX 函数调用获取 rfx-field-list。 这是 SELECT 语句的结果,除非在运行时将其替换为重写版本,不过也可以使用参数或筛选器修改默认语句。

注意

如果指定包含(或可能包含)空格的列名称,则必须将名称括在方括号中。 例如,名称“First Name”应为“[First Name]”。

若要重写默认 SELECT 语句,请在调用 Open 时传递包含完整 SELECT 语句的字符串。 记录集使用所提供的字符串,而不是构造自己的默认字符串。 如果替换语句包含 WHERE 子句,请不要在 m_strFilter 中指定筛选器,因为这样做之后会有两个 filter 语句。 同样,如果替换语句包含 ORDER BY 子句,请不要在 m_strSort 中指定排序,这样就不会有两个 sort 语句。

注意

如果在筛选器中使用文字字符串(或 SQL 语句的其他部分),则必须使用特定于 DBMS 的文字前缀和文字后缀字符将这些字符串“引起来”(括在指定分隔符中)。

对于外部联接等操作,可能还会遇到特殊语法要求,具体取决于 DBMS。 使用 ODBC 函数从 DBMS 驱动程序获取此信息。 例如,针对 SQL_VARCHAR 等特定数据类型调用 ::SQLGetTypeInfo 以请求 LITERAL_PREFIX 和 LITERAL_SUFFIX 字符。 如果要编写与数据库无关的代码,请参阅 ODBC 程序员参考中的附录 C:SQL 语法以获取详细的语法信息。

除非你传递自定义 SQL 语句,否则记录集对象会构造用于选择记录的 SQL 语句。 完成此操作的方式主要取决于在 Open 成员函数的 lpszSQL 参数中传递的值。

SQL SELECT 语句的一般格式为:

SELECT [ALL | DISTINCT] column-list FROM table-list
    [WHERE search-condition][ORDER BY column-list [ASC | DESC]]

将 DISTINCT 关键字添加到记录集的 SQL 语句的一种方法是将此关键字嵌入到 DoFieldExchange 中的第一个 RFX 函数调用中。 例如:

...
    RFX_Text(pFX, "DISTINCT CourseID", m_strCourseID);
...

注意

仅对打开为只读的记录集使用此方法。

重写 SQL 语句

下表显示了 lpszSQL 参数为 Open 的各种可能性。 表后对表中的各案例进行了解释。

lpszSQL 参数及生成的 SQL 字符串

案例 传入 lpszSQL 的内容 生成的 SELECT 语句
1 Null SELECT rfx-field-list FROM table-name

CRecordset::Open 调用 GetDefaultSQL 获取表名称。 生成的字符串是案例 2 到 5 中的一个,具体取决于 GetDefaultSQL 返回的内容。
2 表名称 SELECT rfx-field-list FROM table-name

字段列表取自 DoFieldExchange 中的 RFX 语句。 如果 m_strFilterm_strSort 不为空,则添加 WHERE 和/或 ORDER BY 子句。
3 * 完整的 SELECT 语句,但没有 WHERE 或 ORDER BY 子句 如所传递内容。 如果 m_strFilterm_strSort 不为空,则添加 WHERE 和/或 ORDER BY 子句。
4 * 完整的 SELECT 语句,且包含 WHERE 和/或 ORDER BY 子句 如所传递内容。 m_strFilter 和/或 m_strSort 必须保持为空,否则将生成两个 filter 和/或 sort 语句。
5 * 对存储过程的调用 如所传递内容。

* m_nFields 必须小于或等于 SELECT 语句中指定的列数。 SELECT 语句中指定的每列的数据类型必须与相应 RFX 输出列的数据类型相同。

案例 1 lpszSQL 为 NULL

记录集选择取决于 CRecordset::Open 调用 GetDefaultSQL 时返回的内容。 案例 2 到 5 介绍了可能的字符串。

案例 2 lpszSQL 为表名称

记录集使用记录字段交换 (RFX) 根据记录集类 DoFieldExchange 重写中的 RFX 函数调用提供的列名称生成列列表。 如果使用了向导来声明记录集类,则此案例的结果与案例 1 相同(前提是传递向导中指定的同一表名称)。 如果不使用向导编写类,则案例 2 是构造 SQL 语句的最简单方法。

以下示例将构造一个从 MFC 数据库应用程序选择记录的 SQL 语句。 当框架调用 GetDefaultSQL 成员函数时,该函数返回表的名称 SECTION

CString CEnrollSet::GetDefaultSQL()
{
    return "SECTION";
}

若要为 SQL SELECT 语句获取列的名称,框架将调用 DoFieldExchange 成员函数。

void CEnrollSet::DoFieldExchange(CFieldExchange* pFX)
{
    pFX->SetFieldType(CFieldExchange::outputColumn);
    RFX_Text(pFX, "CourseID", m_strCourseID);
    RFX_Text(pFX, "InstructorID", m_strInstructorID);
    RFX_Text(pFX, "RoomNo", m_strRoomNo);
    RFX_Text(pFX, "Schedule", m_strSchedule);
    RFX_Text(pFX, "SectionNo", m_strSectionNo);
}

完成后,SQL 语句如下所示:

SELECT CourseID, InstructorID, RoomNo, Schedule, SectionNo
    FROM SECTION

案例 3 lpszSQL 为 SELECT/FROM 语句

手动指定列列表,而不是依赖于 RFX 进行自动构造。 在以下情况下可能需要执行此操作:

  • 要指定 SELECT 后面的 DISTINCT 关键字时

    列列表应与 DoFieldExchange 中所列的列名称和类型的顺序一致。

  • 有理由使用 ODBC 函数 ::SQLGetData 手动检索列值而不依赖 RFX 来绑定和检索列时。

    例如,可能需要容纳分发应用程序后应用程序客户向数据库表添加的新列。 需要添加这些额外的字段数据成员,而这些成员在你使用向导声明类时是未知的。

    列列表应与 DoFieldExchange 中所列的列名称和类型的顺序一致,后跟手动绑定列的名称。 有关详细信息,请参阅记录集:动态绑定数据列 (ODBC)

  • 要通过在 FROM 子句中指定多个表来联接表时。

    有关信息和示例,请参阅数据集:执行联接 (ODBC)

案例 4 lpszSQL 为带 WHERE 和/或 ORDER BY 的 SELECT/FROM

指定所有内容:列列表(基于 DoFieldExchange 中的 RFX 调用)、表列表以及 WHERE 和/或 ORDER BY 子句的内容。 如果以这种方式指定 WHERE 和/或 ORDER BY 子句,请不要使用 m_strFilter 和/或 m_strSort

案例 5 lpszSQL 为存储过程调用

如果需要调用预定义查询(例如 Microsoft SQL Server 数据库中的存储过程),则必须在传递给 lpszSQL 的字符串中写入 CALL 语句。 向导不支持声明用于调用预定义查询的记录集类。 并非所有预定义查询都返回记录。

如果预定义查询未返回记录,可以直接使用 CDatabase 成员函数 ExecuteSQL。 对于返回记录的预定义查询,还必须为过程返回的任何列在 DoFieldExchange 中手动写入 RFX 调用。 RFX 调用必须与预定义查询具有相同的顺序,并且返回相同的类型。 有关详细信息,请参阅记录集:为预定义查询声明一个类 (ODBC)

另请参阅

SQL:SQL 和 C++ 数据类型 (ODBC)
SQL:进行直接 SQL 调用 (ODBC)