我想创建一个自定义函数以这种方式使用:
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();
我需要标准差和其他统计函数,但为了简单起见,我们使用“总和的平方根”。基于 “将 SQLite 与 FireDAC 结合使用”教程我添加了:
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
循环来对所有值求和?
如何进行
循环来汇总所有值?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 not sure if FireDAC provides a nicer wrapper for this call!
double* sum = static_cast<double*>(sqlite3_aggregate_context(AOutput->Handle, sizeof(double)));
if (!sum)
{
AOutput->ErrorCode = ...;
AOutput->ErrorText = ...;
return;
}
//
*sum += AInputs->Inputs[0]->AsFloat;
}
void __fastcall TForm1::FDSQLiteFunction1Finalize(TSQLiteFunctionInstance *AFunc,
TObject *&AUserData)
{
// I'm not sure if FireDAC provides a nicer wrapper for this call!
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;