SQL: レコードセットの SQL ステートメントのカスタマイズ (ODBC)
このトピックでは、次の内容について説明します。
フレームワークが SQL ステートメントを構築する方法
SQL ステートメントをオーバーライドする方法
Note
この情報は、MFC ODBC クラスに該当します。 MFC DAO クラスを使っている場合、DAO ヘルプの "Microsoft Jet Database Engine 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]
ここで、table-name
は GetDefaultSQL
を呼び出すことによって取得され、rfx-field-list
は、DoFieldExchange
の RFX 関数呼び出しから取得されます。 これは、実行時にオーバーライドするバージョンに置き換える場合を限り、SELECT ステートメントに対して取得しますが、パラメーターまたはフィルターを使用して既定のステートメントを変更することもできます。
Note
スペースを含む (または含まれる可能性がある) 列名を指定する場合は、名前を角かっこで囲む必要があります。 たとえば、名前 "First Name" は "[First Name]" である必要があります。
既定の SELECT ステートメントをオーバーライドするには、Open
を呼び出す際に、完全な SELECT ステートメントを含む文字列を渡します。 レコードセットでは、独自の既定の文字列を作成する代わりに、指定した文字列を使用します。 置換ステートメントに WHERE 句が含まれている場合は、2 つのフィルター ステートメントが含まれるため、m_strFilter
でフィルターを指定しない必要があります。 同様に、置換ステートメントに ORDER BY 句が含まれている場合は、m_strSort
で並べ替えを指定し、2 つの並べ替えステートメントが含まれるのを確認してください。
Note
フィルター (または 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]]
レコードセットの SQL ステートメントに DISTINCT キーワードを追加する方法の 1 つは、DoFieldExchange
の最初の RFX 関数呼び出しにキーワードを埋め込む方法です。 次に例を示します。
...
RFX_Text(pFX, "DISTINCT CourseID", m_strCourseID);
...
Note
この手法は、読み取り専用として開いたレコードセットでのみ使用します。
SQL ステートメントのオーバーライド
次の表は、Open
への lpszSQL パラメーターの可能性を示しています。 表のケースについては、次の表で説明します。
lpszSQL パラメーターと結果のSQL文字列
ケース | lpszSQL で渡す情報 | 結果の SELECT ステートメント |
---|---|---|
1 | NULL | SELECT rfx-field-list FROM table-nameCRecordset::Open は GetDefaultSQL を呼び出してテーブル名を取得します。 結果の文字列は、GetDefaultSQL が返す内容に応じて、ケース 2 から 5 の 1 つになります。 |
2 | テーブル名 | SELECT rfx-field-list FROM table-name フィールド リストは、 DoFieldExchange の RFX ステートメントから取得されます。 m_strFilter と m_strSort が空ではない場合は、WHERE および/または ORDER BY 句を追加します。 |
3 * | SELECT ステートメントが完全で、WHERE 句または ORDER BY 句がない場合 | 渡されたとおり。 m_strFilter と m_strSort が空ではない場合は、WHERE および/または ORDER BY 句を追加します。 |
4 * | WHERE 句や ORDER BY 句を含む完全な SELECT 文 | 渡されたとおり。 m_strFilter および/または m_strSort は空のままにする必要があります。または、2 つのフィルター ステートメントや並べ替えステートメントが生成されます。 |
5 * | ストアド プロシージャの呼び出し | 渡されたとおり。 |
* m_nFields
は、SELECT ステートメントで指定された列数以下でなければなりません。 SELECT ステートメントで指定する各列のデータ型は、対応する RFX 出力列のデータ型と同じである必要があります。
ケース 1 lpszSQL = NULL
レコードセットの選択は、GetDefaultSQL
が CRecordset::Open
を呼び出したときに何を返すかに依存します。 ケース 2 ~ 5 では、考えられる文字列が記述されています。
ケース 2 lpszSQL = テーブル名
レコードセットは、レコード フィールド交換 (RFX) を使用して、レコードセット クラスの DoFieldExchange
のオーバーライドで RFX 関数呼び出しで指定された列名から列リストを作成します。 ウィザードを使用してレコードセット クラスを宣言した場合、このケースの結果はケース 1 と同じです (ウィザードで指定したのと同じテーブル名を渡す場合)。 ウィザードを使用してクラスを記述しない場合は、大文字と小文字の区別ステートメントを作成する最も簡単なSQLケース 2 です。
次の例では、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
に一覧表示されているのと同じ順序で列名と型と一致する必要があります。列をバインドおよび取得するために RFX に依存するのではなく、ODBC 関数
::SQLGetData
を使用して列の値を手動で取得する理由があります。たとえば、アプリケーションの顧客を、アプリケーションの分散後にデータベース テーブルに追加した新しい列に格納したい場合があります。 これらの追加のフィールド データ メンバーを追加する必要があります。これは、ウィザードでクラスを宣言した時点では知られていませんでした。
列の一覧は、
DoFieldExchange
に記載されているのと同じ順序で列の名前と型に一致し、その後に手動でバインドされた列の名前と一致する必要があります。 詳細については、「レコードセット: データ列を動的に結びつける方法 (ODBC)」を参照してください。FROM 句で複数のテーブルを指定してテーブルを結合する必要があります。
詳細と例については、「レコードセット: 結合 (ODBC)」を参照してください。
ケース 4 lpszSQL = SELECT/FROM プラス WHERE または ORDER BY
列リスト (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)」を参照してください。