Enviando dados como um parâmetro com valor de tabela com todos os valores na memória (ODBC)
Este tópico descreve como enviar dados a um procedimento armazenado como um parâmetro com valor de tabela quando todos os valores estão na memória.
Pré-requisito
Esse procedimento supõe que o seguinte Transact-SQL tenha sido executado no servidor:
create type TVParam as table(ProdCode integer, Qty integer)
create procedure TVPOrderEntry(@CustCode varchar(5), @Items TVPParam,
@OrdNo integer output, @OrdDate datetime output)
as
set @OrdDate = GETDATE();
insert into TVPOrd (OrdDate, CustCode)
values (@OrdDate, @CustCode) output OrdNo);
select @OrdNo = SCOPE_IDENTITY();
insert into TVPItem (OrdNo, ProdCode, Qty)
select @OrdNo, @Items.ProdCode, @Items.Qty
from @Items
Para enviar os dados
Declare variáveis para os parâmetros SQL. Neste caso, o valor de tabela é mantido completamente na memória e, dessa forma, os valores para as colunas do valor de tabela são declarados como matrizes.
SQLRETURN r; // Variables for SQL parameters. #define ITEM_ARRAY_SIZE 20 SQLCHAR CustCode[6]; SQLCHAR *TVP = (SQLCHAR *) "TVParam"; SQLINTEGER ProdCode[ITEM_ARRAY_SIZE], Qty[ITEM_ARRAY_SIZE]; SQLINTEGER OrdNo; char OrdDate[23]; // Variables for indicator/length variables associated with parameters. SQLLEN cbCustCode, cbTVP, cbProdCode[ITEM_ARRAY_SIZE], cbQty[ITEM_ARRAY_SIZE], cbOrdNo, cbOrdDate;
Associe os parâmetros. A associação de parâmetros é um processo de dois estágios quando são usados parâmetros com valor de tabela. No primeiro estágio, os parâmetros das etapas para o procedimento armazenado são associados de maneira normal, como a seguir.
// Bind parameters for call to TVPOrderEntryDirect. // 1 - Custcode input r = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,SQL_VARCHAR, SQL_C_CHAR, 5, 0, CustCode, sizeof(CustCode), &cbCustCode); // 2 - Items TVP r = SQLBindParameter(hstmt, 2,// ParameterNumber SQL_PARAM_INPUT,// InputOutputType SQL_C_DEFAULT,// ValueType SQL_SS_TABLE,// Parametertype ITEM_ARRAY_SIZE,// ColumnSize: For a table-valued parameter this is the row array size. 0,// DecimalDigits: For a table-valued parameter this is always 0. TVP,// ParameterValuePtr: For a table-valued parameter this is the type name of the //table-valued parameter, and also a token returned by SQLParamData. SQL_NTS,// BufferLength: For a table-valued parameter this is the length of the type name or SQL_NTS. &cbTVP);// StrLen_or_IndPtr: For a table-valued parameter this is the number of rows actually used. // 3 - OrdNo output r = SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT,SQL_INTEGER, SQL_C_LONG, 0, 0, &OrdNo, sizeof(SQLINTEGER), &cbOrdNo); // 4 - OrdDate output r = SQLBindParameter(hstmt, 4, SQL_PARAM_OUTPUT,SQL_TYPE_TIMESTAMP, SQL_C_CHAR, 23, 3, &OrdDate, sizeof(OrdDate), &cbOrdDate);
O segundo estágio da associação de parâmetros é associar as colunas para o parâmetro com valor de tabela. O foco do parâmetro é definido primeiro para o ordinal do parâmetro com valor de tabela. Em seguida, as colunas do valor da tabela são associadas usando SQLBindParameter da mesma maneira que seriam se elas fossem parâmetros do procedimento armazenado, mas com ordinais de coluna para ParameterNumber. Se houvesse mais parâmetros com valor de tabela, nós definiríamos o foco para cada um deles sucessivamente e associaríamos suas colunas. Finalmente, o foco de parâmetro é redefinido para 0.
// Bind columns for the table-valued parameter (param 2). // First set focus on param 2. r = SQLSetStmtAttr(hstmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER) 2, SQL_IS_INTEGER); // Col 1 - ProdCode r = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,SQL_INTEGER, SQL_C_LONG, 0, 0, ProdCode, sizeof(SQLINTEGER), cbProdCode); // Col 2 - Qty r = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT,SQL_INTEGER, SQL_C_LONG, 0, 0, Qty, sizeof(SQLINTEGER), cbQty); // Reset param focus. r = SQLSetStmtAttr(hstmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER) 0, SQL_IS_INTEGER);
Popule os buffers de parâmetro. cbTVP é definido como o número de linhas a serem enviadas ao servidor.
// Populate parameters. cbTVP = 0; // Number of rows available for input. strcpy_s((char *) CustCode, sizeof(CustCode), "CUST1"); cbCustCode = SQL_NTS; ProdCode[cbTVP] = 1215;cbProdCode[cbTVP] = sizeof(SQLINTEGER); Qty[cbTVP] = 5;cbQty[cbTVP] = sizeof(SQLINTEGER); cbTVP++; // Number of rows available for input ProdCode[cbTVP] = 1017;cbProdCode[cbTVP] = sizeof(SQLINTEGER); Qty[cbTVP] = 2;cbQty[cbTVP] = sizeof(SQLINTEGER); cbTVP++; // Number of rows available for input.
Chame o procedimento:
// Call the procedure. r = SQLExecDirect(hstmt, (SQLCHAR *) "{call TVPOrderEntry(?, ?, ?, ?)}",SQL_NTS);