快速报告显示ADOQuery中的错误数据

时间:2013-08-07 21:43:10

标签: delphi fastreport

我遇到快速报告显示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

快速报告仅显示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附加到附加到frxReport2的frxDBDataset2。我没有采取任何措施来改变查询中的结果。

不,我在报告中没有代码,它全部是从向导生成的。

2 个答案:

答案 0 :(得分:2)

FastReport无法仅在SHIP_DATENULL的情况下显示记录,因为如果WHEREDate1您的查询不应根据Date2子句返回它们正确分配。这意味着您的数据集和FastReport没有正确连接,或者您的代码中的某些内容为BETWEEN子句指定日期值是错误的,并且日期未正确提供给查询。

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

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

您设置SQL的方式实际上是无法控制的。当您尝试在代码中管理自己的引用时,它是不可读的和不可维护的。

您应该使用参数,这些参数首先保护您免受SQL注入,但也允许数据库驱动程序为您正确格式化引用的值和日期,并保持可读性。 (你也可以使用可读的名字作为参数,这样当你看到他们六个月之后你会知道他们的意思。)

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;

答案 1 :(得分:0)

当我开始遇到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;