REF_CURSOR
ストアド プロシージャ変数の出力からテーブルを作成できるパッケージがあります。クライアント アプリケーションに大量の結果を返すために、これを DevPress XPO ソースで使用します。
以前はソリッド テーブルを作成し、キーを追加してインデックスを作成し、新しいテーブル名を XPO ソースに提供されたクライアントに返しましたが、機能しています。ただし、ソリッド テーブルを使用するのは最善の解決策ではないため、GTT の使用を開始しました。
TOAD でパッケージを実行すると、データは保持されますが、C# からコマンドを実行すると、実行直後にテーブルにデータがありません。接続はまだ閉じられていないため、データが存在しない理由は 100% わかりません。
すべての実行が同じセッションで行われることを確認するために設定できる接続コンテキストに何かがありますか? テーブルに入力するステートメントがありexecute immediate
、パッケージを実行するときに TOAD が同じコンテキストを使用する可能性があると思います。
これが私のコードの一部です:
FUNCTION Build_Table_from_Cursor(REF_CURSOR SYS_REFCURSOR, ID NUMBER, AddKeyField CHAR) RETURN VARCHAR2 AS
QueryCursor SYS_REFCURSOR;
CursorNumber NUMBER;
p_tablename varchar2(30);
pk_name varchar2(30);
BEGIN
QueryCursor := REF_CURSOR;
CursorNumber := DBMS_SQL.TO_CURSOR_NUMBER(QueryCursor);
p_tablename := 'TEMPTABLE';
UTIL.create_table_from_cursor(CursorNumber, p_tablename); --This creates the GTT with all the columns
Execute immediate 'TRUNCATE TABLE ' || p_tablename; --To Add the key this must be done otherwise there is an error
pk_name := substr(p_tablename, INSTR(p_tablename, '.') + 1);
IF(AddKeyField = 'Y') THEN --Sometimes the Key field already exists
EXECUTE IMMEDIATE 'ALTER TABLE ' || p_tablename || ' ADD (KEY_FIELD_ NUMBER)';
END IF;
EXECUTE IMMEDIATE 'CREATE UNIQUE INDEX ' || p_tablename || 'KEY_INDEX ON ' || p_tablename || ' (KEY_FIELD_)';
EXECUTE IMMEDIATE 'ALTER TABLE ' || p_tablename || ' ADD CONSTRAINT pk_' || pk_name || ' PRIMARY KEY( KEY_FIELD_ )';
QueryCursor := DBMS_SQL.TO_REFCURSOR(CursorNumber);
PDS.UTIL.POPULATE_TABLE_FROM_CURSOR(QueryCursor, p_tablename, 1000); --This populates the table
EXECUTE IMMEDIATE 'UPDATE ' || p_tablename || ' SET KEY_FIELD_ = ROWNUM';
COMMIT;
return p_tablename;
END Build_Table_from_Cursor;
これは、TOAD で実行すると完全に機能します。
これを実行すると
using (var conn = factory.CreateConnection(Dal.ConnectionStrings[connectionString].ConnectionString))
{
conn.Open();
using (var cmd = factory.CreateCommand(CommandType.StoredProcedure, storedProcedureName))
{
var storedProcedureRow = commandExecuteDataSet.StoredProcedure[0];
foreach (var parametersRow in commandExecuteDataSet.Parameters)
{
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter(parametersRow.Name, parametersRow.Value ?? "", GetDBTypeFromString(parametersRow.OracleDbType)));
}
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter(storedProcedureRow.RefCursorName, DbType.Object, ParameterDirection.Output, true));
cmd.ExecuteNonQuery();
var refCursor = cmd.Parameters[storedProcedureRow.RefCursorName].Value;
cmd.Parameters.Clear();
cmd.CommandText = "SERVERMODE_UTIL.Build_Table_from_Cursor";
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter("REF_CURSOR", refCursor));
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter("ID", biID));
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter("AddKeyField", "Y"));
cmd.Parameters.Add(CustomDbProviderFactory.CreateParameter("p_tablename", DbType.String, ParameterDirection.ReturnValue));
cmd.ExecuteNonQuery();
var tempTableName = cmd.Parameters["p_tablename"].Value.ToString();
tempTableName = tempTableName.Substring(tempTableName.IndexOf(".") + 1);
}
}
より大きなパッケージの一部として、これは GTT を作成するために実行されるコードです
l_statement := 'CREATE GLOBAL TEMPORARY TABLE ' || l_tablename || ' (' || CHR(13) || CHR(10) || l_statement || CHR(13) || CHR(10) || ') ON COMMIT PRESERVE ROWS';
execute immediate l_statement;