【问题标题】:Fast Report displaying incorrect data from ADOQuery快速报告显示来自 ADOQuery 的错误数据
【发布时间】:2013-08-09 05:20:28
【问题描述】:

快速报告显示来自 ADOquery 的错误数据时遇到问题。我使用以下 sql.text

SELECT * FROM JOB_DATA 
INNER JOIN CUSTOMER ON JOB_DATA.CUST_CODE = CUSTOMER.CUST_CODE 
WHERE JOB_DATA.SHIP_DATE Between [Date1] And [Date2] 
ORDER by SHIP_DATE

Fast Report 仅显示 SHIP_DATE = null 的数据。

如果我抛出一个 TDBgrid 并将其附加到附加到同一个 ADOquery 的数据源,那么 dbgrid 会显示完全正确的信息。

我没有想法,有什么建议吗?

回答有关日期来源的问题:

var
  date1:string;
  date2:string;
  sql_str:string;
begin
  date1:=inputbox('Date Range','Enter Beginning Date','');
  Try
    StrToDate(date1);
  Except 
    On EConvertError Do
    Begin
      MessageDlg('Please enter a valid date.  Format xx/xx/xx',
         mtError, [mbOK], 0);
      //ShowMessage('Please enter a valid date.  Format `enter code here`xx/xx/xx');
      Exit;
    End;
  End;

  date2:=inputbox('Date Range','Enter Ending Date','');
  Try
    StrToDate(date2);
  Except 
    On EConvertError Do
    Begin
      MessageDlg('Please enter a valid date.  Format xx/xx/xx',
          mtError, [mbOK], 0);
      //ShowMessage('Please enter a valid date.  Format `enter code here`xx/xx/xx');
      Exit;
    End;
  End;

  sql_str:= 'SELECT * FROM JOB_DATA INNER JOIN CUSTOMER ON ' +
            'JOB_DATA.CUST_CODE = CUSTOMER.CUST_CODE ' +
            'WHERE JOB_DATA.SHIP_DATE Between ';
  sql_str:= sql_str+ ''' ';
  sql_st:=sql_str + date1;
  sql_str:= sql_str+ '''';
  sql_str:= sql_str+ ' AND ';
  sql_str:= sql_str+ ''' ';
  sql_str:= sql_str+ date2;
  sql_str:= sql_str+ ' ''';

  with ADOQuery5 do 
  begin
    Close;
    SQL.Clear;
    SQL.text:= sql_str;
    Open;
  end;
  frxreport2.ShowReport();
end;

ADOquery 附加到 frxDBDataset2,frxDBDataset2 附加到 frxReport2。我没有做任何事情来改变查询中的结果。

不,我在报告中没有代码,它都是由向导生成的。

【问题讨论】:

  • 您如何将报告与数据联系起来? FR 只显示您的查询包含的内容,除非您自己做一些改变。 Date1Date2 来自哪里?您的问题是 FR 做错了什么,但您根本没有提供有关 FR 的信息;您刚刚显示了一个查询并说“FR 显示不正确的数据”,没有我们可以用来尝试帮助您的详细信息。
  • ADOquery 附加到 frxreport2 附加的 frxDBDataset2 我从 date1:=inputbox('Date Range','Enter Starting Date','');
  • edit您的问题在此处添加任何其他详细信息,因此我们不必从 cmets 中挑选它们并且可以正确格式化它们。这只是信息的一半。 date1 如何从您显示的行中获取查询的一部分?它只是没有出现在那里,因为您从inputbox 获得了一个值。你有任何代码是报告本身的一部分吗?如果您需要帮助,请提供详细信息,以便我们提供帮助。请不要让我们乞求每一条信息。
  • 报告完全由向导生成。我在 FR 中没有写代码。无论我输入什么日期范围 FR 只显示 SHIP_DATE = null 的数据,但 dbgrid 正确显示日期范围。
  • 我发布了一个可能有帮助的答案。如果没有,至少您可以更新代码以提高可读性。 :-) (当您在此处发布代码时,您应该正确格式化它以便我们可以阅读它。单击标有? 的橙色小按钮向您展示如何操作,您可以在输入代码的下方预览它这样你就会知道它看起来是正确的。如果我们看不懂它,那就更难提供帮助了。我是通过修复你发布的最后一个代码来帮助你的。)

标签: delphi fastreport


【解决方案1】:

FastReport 不能仅显示 SHIP_DATENULL 的记录,因为如果正确分配了 Date1Date2,则您的查询不应根据您的 WHERE 子句返回它们。这意味着您的数据集和 FastReport 未正确连接,或者您的代码中为 BETWEEN 子句分配日期值的某些内容是错误的,并且日期未正确提供给查询。

开始查找的第一个地方是确保所有报告列都正确分配了正确的TfrxDataSet 和正确的数据库列。 (单击报告项(文本对象或任何可能的内容),并检查其DataSetDataField 属性以确保它们正确。)

如果这不是问题,则可能是您构建查询的方式,它可能没有正确格式化 ADO 的日期。 (您只是使用任何格式来传递 StrToDate 调用而不引发异常。)

您设置 SQL 的方式确实不可取。当您尝试管理在代码中引用自己时,它是不可读且不可维护的。

您应该使用参数,这首先可以保护您免受 SQL 注入,但也允许数据库驱动程序为您正确格式化引用的值和日期并保持可读性。 (您也可以为参数使用易读的名称,这样当您在 6 个月后看到它们时就会知道它们的含义。)

var
  // Your other variable declarations here
  StartDate, EndDate: TDateTime;
begin
  Date1 := InputBox(Whatever);
  try
    StartDate := StrToDate(Date1);
  except
    // Handle EConvertError
  end;
  Date2 := InputBox(Whatever);
  try
    EndDate := StrToDate(Date2);
  except
    // Handle EConvertError
  end;

  sql_str := 'SELECT * FROM JOB_DATA J'#13 +
             'INNER JOIN CUSTOMER C'#13 +
             'ON J.CUST_CODE = C.CUST_CODE'#13 +
             'WHERE J.SHIP_DATE BETWEEN :StartDate AND :EndDate';

  with ADOQuery5 do 
  begin
    Close;
    // No need to clear. If you're using the same query more than once,
    // move the SQL assignment and the Parameter.DataType somewhere
    // else, and don't set them here.
    // The query can be reused just by closing, changing parameter values,
    // and reopening.
    SQL.Text := sql_str;
    with Parameters.ParamByName('StartDate') do
    begin
      DataType := ftDate;
      Value := StartDate;
    end;
    with Parameters.ParamByName('EndDate') do
    begin
      DataType := ftDate;
      Value := EndDate;
    end;
    Open;
  end;
  frxReport2.ShowReport;
end;

【讨论】:

  • Ken,谢谢,但结果仍然相同。我放在表格上用于测试的 dbgrid 显示了请求的日期范围内的记录,而报告只显示了 SHIP_DATE=null 的记录。这可能是我的 FR 版本中的错误吗?
  • 我不知道怎么做。如果您没有在代码中做任何更改来更改任何内容,FR 只会显示查询结果中的内容。如果您看到 null SHIP_DATE 值,则说明您的查询有问题。尝试保持 DBGrid 连接并同时执行ShowReport,调整报表预览的大小,以便您可以同时看到网格和报表。当你比较它们时,你会看到什么?您确定 FR 显示的是数据中的 SHIP_DATE 吗? (您会不会错过将报告列连接到查询列?)
  • Ken,谢谢,您对连接到查询列的报告列的评论很有帮助。不知道为什么,但是报告一直跳到 frxDBDataset1 而不是一直连接到 frxDBDataset2。不知道为什么,但我删除了 frxReport2 并重新启动它,它现在可以工作了。
  • 我添加了一个新段落(目前是第二个段落)来提及确保事情正确连接。 :-)
【解决方案2】:

当我开始遇到 ADO 问题时,我会记录信息。

您需要创建自己的记录器...但这是开玩笑的...请注意,它将记录传递给查询的参数值,包括 SQL。

procedure TLogger.SetUpConnectionLogging(aParent: TComponent);
var
  a_Index: integer;
begin
  for a_Index := 0 to aParent.ComponentCount - 1 do
    if aParent.Components[a_Index] is TAdoConnection then
    begin
      TAdoConnection(aParent.Components[a_Index]).OnWillExecute :=  WillExecute;
      TAdoConnection(aParent.Components[a_Index]).OnExecuteComplete :=  ExecuteComplete;
    end;
end;

procedure TLogger.ExecuteComplete(Connection: TADOConnection;
  RecordsAffected: Integer; const Error: Error; var EventStatus: TEventStatus;
  const Command: _Command; const Recordset: _Recordset);
var
  a_Index: integer;
begin
  AddLog('AdoConnection ExecuteComplete', True);
  AddLog('Execution In MilliSeconds', IntToStr(MilliSecondsBetween(Time, FDif)));
  AddLog('Execution In Seconds', IntToStr(SecondsBetween (Time, FDif)));
  AddLog('Execution In Minutes', IntToStr(MinutesBetween (Time, FDif)));
  AddLog('CommandText', Command.CommandText);
  if Assigned(Command) then
  begin
    AddLog('Param Count', IntToStr(Command.Parameters.Count));
    for a_Index := 0 to Command.Parameters.Count - 1 do
    begin
      AddLog(Command.Parameters.Item[a_Index].Name, VarToWideStr(Command.Parameters.Item[a_Index].Value));
    end;
    AddLog('CommandType', GetEnumName(TypeInfo(TCommandType),Integer(Command.CommandType)));
  end;
  AddLog('EventStatus', GetEnumName(TypeInfo(TEventStatus),Integer(EventStatus)));
  if Assigned(RecordSet) then
  begin
    AddLog('CursorType', GetEnumName(TypeInfo(TCursorType),Integer(Recordset.CursorType)));
    AddLog('LockType',  GetEnumName(TypeInfo(TADOLockType),Integer(Recordset.LockType)));
  end;
  AddLog('RecordsAffected',  IntToStr(RecordsAffected));
  AddLog('AdoConnection ExecuteComplete', False);
end; 

procedure TLogger.WillExecute(Connection: TADOConnection;
  var CommandText: WideString; var CursorType: TCursorType;
  var LockType: TADOLockType; var CommandType: TCommandType;
  var ExecuteOptions: TExecuteOptions; var EventStatus: TEventStatus;
  const Command: _Command; const Recordset: _Recordset);
begin
  AddLog('Connection WillExecute', True);
  AddLog('Connection Name', Connection.Name);
  AddLog('CommandText', CommandText);
  AddLog('CommandType', GetEnumName(TypeInfo(TCommandType),Integer(CommandType)));
  AddLog('EventStatus', GetEnumName(TypeInfo(TEventStatus),Integer(EventStatus)));
  AddLog('CursorType', GetEnumName(TypeInfo(TCursorType),Integer(CursorType)));
  AddLog('Connection WillExecute', False);
  FDif :=  Time;
end;

【讨论】:

  • 这如何回答有关 FastReports 为何不显示预期值的问题?
  • @Ken White 它可以让您知道报表正在运行什么 SQL...您可以确认报表正在运行的基础数据集是正确的,而不是您认为是正确的...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-19
相关资源
最近更新 更多