假设我想创建一个自定义的“总和的平方根”函数以这种方式使用:
FDQuery1->SQL->Text = "SELECT SQRT_SUM(FIELD_1) FROM TABLE_1 WHERE ID = 1";
FDQuery1->Open();
ShowMessage(Form1->FDQuery1->Fields->Fields[0]->AsFloat);
FDQuery1->Close();
实际上,我需要实现标准差和其他一些统计函数,但为了简单起见,我们使用“总和的平方根”。
基于“Using SQLite with FireDAC”tutorial(“自定义函数”部分),我添加了以下代码:
void __fastcall TForm1::FDSQLiteFunction1Calculate(TSQLiteFunctionInstance *AFunc,
TSQLiteInputs *AInputs, TSQLiteOutput *AOutput, TObject *&AUserData)
{
double sum = 0;
for (long i = 0; i < AInputs->Count; i++) sum += AInputs->Inputs[i]->AsFloat;
AOutput->AsFloat = sqrt(sum);
}
FDSQLiteFunction1->DriverLink = FDPhysSQLiteDriverLink1;
FDSQLiteFunction1->FunctionName = 'SQRT_SUM';
FDSQLiteFunction1->Aggregated = true;
FDSQLiteFunction1->ArgumentsCount = 1;
FDSQLiteFunction1->OnCalculate = FDSQLiteFunction1Calculate;
FDSQLiteFunction1->Active = true;
但是该函数是为每一行调用的,而不是一次,除非使用全局变量,否则我无法获得我想要的值。
如何进行
for
循环来汇总所有值?
您误解了
OnCalculate
事件在您的情况下如何运作。
对于非聚合函数,
OnCalculate
事件确实按照您的预期工作。它仅被调用 1 次,其中 AInputs
包含所有输入值。 该事件必须输出最终计算值。
但是,对于 aggregate 函数,当 SQLite 迭代正在聚合的数据集时,每个步骤(即记录)都会调用
OnCalculate
事件,因此 AInputs
将仅包含记录的输入值在当前步骤中。 OnCalculate
事件还无法返回最终的计算值,因此您需要在迭代完成后使用OnFinalize
事件来计算最终值。
请参阅 SQLite 的文档 - 应用程序定义的 SQL 函数 ,特别是关于 回调 的部分。
尝试更多类似这样的事情:
void __fastcall TForm1::FDSQLiteFunction1Calculate(TSQLiteFunctionInstance *AFunc,
TSQLiteInputs *AInputs, TSQLiteOutput *AOutput, TObject *&AUserData)
{
// I'm note sure if FireDAC provides a nicer wrapper for this!
double* sum = static_cast<double*>(sqlite3_aggregate_context(AOutput->Handle, sizeof(double)));
if (!sum)
{
AOutput->ErrorCode = ...;
AOutput->ErrorText = ...;
}
else
{
*sum += AInputs->Inputs[0]->AsFloat;
}
}
void __fastcall TForm1::FDSQLiteFunction1Finalize(TSQLiteFunctionInstance *AFunc,
TObject *&AUserData)
{
// I'm note sure if FireDAC provides a nicer wrapper for this!
double* sum = static_cast<double*>(sqlite3_aggregate_context(AOutput->Handle, 0));
AFunc->Output->AsFloat = sum ? sqrt(*sum) : 0.0;
}
FDSQLiteFunction1->DriverLink = FDPhysSQLiteDriverLink1;
FDSQLiteFunction1->FunctionName = 'SQRT_SUM';
FDSQLiteFunction1->Aggregated = true;
FDSQLiteFunction1->ArgumentsCount = 1;
FDSQLiteFunction1->OnCalculate = FDSQLiteFunction1Calculate;
FDSQLiteFunction1->OnFinalize = FDSQLiteFunction1Finalize;
FDSQLiteFunction1->Active = true;