用sql语句好象可以。update tablename (select * from tablename)之类语句

解决方案 »

  1.   

    我做过类似的项目。用SQL实现
    不知你考虑到下级的数据可能是更新的,也可能是新增的。因此,导入数据时必须想到这点。我的作法是,先将目的数据库中的有关记录删去,然后再将下级上报的记录(既有更新的,也有新增的)读入即可。
    这样,更新、新增记录的任务都完成了。具体操作还可细化。要看你的具体情况了。
      

  2.   

    这个问题最好控件来实现。(你可以上delphi super page上去找一找),因为一旦更新未完全更新涉及到两阶段提交问题编程很难控制(恐怕工作量也相当于写一个小项目了)。如果自已写,思想一般是这样:先将数据存成临时文件,再定位(adodataset.locate定位)->更新回去(主键不能更新;用个循环依次存回去,但就怕出事儿(假设断电)这时是提交好还是返回好呢?),我这儿有一个将数据集存成文本文件的控件(for BDE的),但你可以参考他的思想改成for ADO的只需要抄他几段程序即可(但读文件更新回数据库的函数你就得自已写了)不知是否对你有帮助:
    unit kdb2text;interfaceuses SysUtils, Classes, Dialogs, Db, DbTables, BDE;type
      TKDBToTextError = class(Exception)
      end;  TKDatasetToText = class(TComponent)
      private
        FDataSet : TDataSet;
        FDelimiter : char;
        procedure SetDataset(Value : TDataSet);
      protected
        procedure Notification(AComponent: TComponent; Operation: TOperation);override;
      public
        constructor Create(AOwner : TComponent); override;
        destructor Destroy;override;
        procedure Transfer(FileName : string);
      published
        property Dataset : TDataSet read FDataset write SetDataSet;
        property Delimiter : char read FDelimiter write FDelimiter;
      end;  TKDatabaseToText = class(TComponent)
      private
        FDatabaseName : string;
        FDelimiter : char;
        FWorkDir : string;
        FTable : TTable;
        procedure SetWorkDir(Value : string);
        procedure SetDatabaseName(Value : string);
      public
        constructor Create(AOwner : TComponent); override;
        destructor Destroy;override;
        procedure ExportDatabase;
        procedure ImportDatabase;
        procedure ExportTable(TableName : string);
        procedure ImportTable(TableName : string);
      published
        property DatabaseName : string read FDatabaseName write SetDatabaseName;
        property WorkDir : string read FWorkDir write SetWorkDir;
        property Delimiter : char read FDelimiter write FDelimiter;
      end;implementation
    uses FileCtrl;function QuotedString(const S : string; Quote : char) : string;
    var
      i : integer;
    begin
      Result := Quote;
      for i := 1 to Length(S) do
      begin
        Result := Result + S[i];
        if S[i] = Quote then
          Result := Result + Quote;
      end;
      Result := Result + Quote;
    end;//return unquoted string
    function UnquotedString(const S : string; Quote : char) : string;
    var
      i : integer;
    begin
      if (S = '') or (S[1] <> Quote) then
      begin
        Result := S;
        exit;
      end;
      Result := ''; i := 2;
      while i < Length(S) do
      begin
        if S[i] = Quote then
        begin
          if S[i + 1] = Quote then
          begin
            Result := Result + Quote;
            inc(i, 2);
            continue;
          end;
        end;
        Result := Result + S[i];
        inc(i);
      end;
    end;//return delimited text by StringList
    function DelimitedText(Strings : TStrings; Delimiter, Quote : char) : string;
    var
      i : integer;
    begin
      Result := '';
      for i := 0 to Strings.Count - 1 do
      begin
        if i <> 0 then Result := Result + Delimiter;
        Result := Result + QuotedString(Strings[i], Quote);
      end;
    end;procedure ComposeText(const S : string; Delimiter, Quote : char; Strings : TStrings);
    var
      i, prev : integer;
      b : boolean;
    begin
      prev := 0;
      b := false;
      Strings.Clear;
      for i := 1 to Length(S) do
      begin
        if S[i] = Quote then b := not b;
        if not b and (S[i] = Delimiter) then
        begin
          Strings.Add(UnquotedString(Trim(Copy(S, prev + 1, i - prev - 1)), Quote));
          prev := i;
        end;
      end;
      Strings.Add(UnquotedString(Trim(Copy(S, prev + 1, Length(S))), Quote));
    end;//add '\' to path end if it does not exist
    function FixPath(const Path : string) : string;
    begin
      if (Path <> '') and (Path[Length(Path)] <> '\') then
        Result := Path + '\'
      else
        Result := Path;
    end;procedure ClearFileExt(var FileName : string);
    var
      p : integer;
    begin
      p := Length(FileName);
      while (p > 0) and (FileName[p] <> '.') do dec(p);
      if p = 0 then exit;
      Delete(FileName, p, Length(FileName));
    end;procedure ChangeFileExt(var FileName : string; const NewExt :string);
    begin
      ClearFileExt(FileName);
      FileName := FileName + '.' + NewExt;
    end;constructor TKDatasetToText.Create(AOwner : TComponent);
    begin
      inherited Create(AOwner);
      FDataSet := nil;
      FDelimiter := #9;
    end;destructor TKDatasetToText.Destroy;
    begin
      inherited;
    end;procedure TKDatasetToText.SetDataset(Value : TDataSet);
    begin
      if FDataset <> Value then
        FDataset := Value;
    end;procedure TKDatasetToText.Notification(AComponent: TComponent; Operation: TOperation);
    begin
      inherited Notification(AComponent, Operation);
      if (Operation = opRemove) and (AComponent = FDataSet) then
        FDataSet := nil;
    end;procedure TKDatasetToText.Transfer(FileName : string);
    var
      i : integer;
      slOut, slRow : TStrings;
      MS1, MS2 : TMemoryStream;
    begin
      if FDataSet = nil then
        raise TKDBToTextError.Create('Dataset is not specified');
      if not FDataSet.Active then
        raise TKDBToTextError.Create('Dataset is not active');
      slOut := TStringList.Create;
      slRow := TStringList.Create;
      MS1 := TMemoryStream.Create;
      MS2 := TMemoryStream.Create;
      try
        FDataSet.First;
        while not FDataSet.EOF do
        begin
          slRow.Clear;
          for i := 0 to FDataSet.FieldCount - 1 do
          begin
            if not (FDataSet.Fields[i].DataType in [ftBlob, ftMemo, ftGraphic, ftFmtMemo,
                                                  ftParadoxOle, ftDBaseOle, ftTypedBinary]) then
              slRow.Add(FDataSet.Fields[i].AsString)
            else begin
              MS2.Clear;
              (FDataSet.Fields[i] as TBlobField).SaveToStream(MS2);
              MS1.CopyFrom(MS2,0);
              slRow.Add(IntToStr(MS2.Size));
            end;
          end;
          slOut.Add(DelimitedText(slRow, FDelimiter, '"'));
          FDataSet.Next;
        end;
        if ExtractFileExt(FileName) = '' then FileName := FileName + '.txt'; 
        slOut.SaveToFile(FileName);    if MS1.Size > 0 then
        begin
          ChangeFileExt(FileName, 'mem');
          MS1.SaveToFile(FileName);
        end;
      finally
        slRow.Free;
        slOut.Free;
        MS2.Free;
        MS1.Free;
      end;
    end;{TKDatabaseToText}
    constructor TKDatabaseToText.Create(AOwner : TComponent);
    begin
      inherited Create(AOwner);
      FTable := TTable.Create(nil);
      FWorkDir := '';
      FDatabaseName := '';
      FDelimiter := #9;
    end;destructor TKDatabaseToText.Destroy;
    begin
      FTable.Free;
      inherited Destroy;
    end;procedure TKDatabaseToText.SetDatabaseName(Value : string);
    var
      dbDes: DBDesc;
    begin
      FDatabaseName := Value;
      if not (csLoading in ComponentState) then
      begin
        Check(DbiGetDatabaseDesc(PChar(FDatabaseName), @dbDes));
        WorkDir := StrPas(dbDes.szPhyName) + '\TextBkup';
      end;
      FTable.DatabaseName := FDatabaseName;
    end;procedure TKDatabaseToText.SetWorkDir(Value : string);
    begin
      FWorkDir := Value;
    end;{
    function TKDatabaseToText.GetDelimiter : TKTextDelimiter;
    begin
      Result := TypeByDelimiter(FDelimiter);
    end;procedure TKDatabaseToText.SetDelimiter(Value : TKTextDelimiter);
    begin
      FDelimiter := DelimiterByType(Value);
    end;
    }procedure TKDatabaseToText.ExportTable(TableName : string);
    var
      DS2T : TKDataSetToText;
    begin
      ForceDirectories(FWorkDir); //!!!!!!!!!!!!!!!!!!!!!!!!! check
      DS2T := TKDataSetToText.Create(nil);
      try
        FTable.TableName := TableName;
        FTable.Active := true;
        try
          DS2T.Delimiter := Delimiter;
          DS2T.DataSet := FTable;
          ClearFileExt(TableName);
          DS2T.Transfer(FixPath(FWorkDir) + TableName);
        finally
          FTable.Active := false;
        end;  
      finally
        DS2T.Free;
      end;
    end;procedure TKDatabaseToText.ExportDatabase;
    var
      slTbls : TStrings;
      i : integer;
    begin
      slTbls := TStringList.Create;
      try
        Session.GetTableNames(FDatabaseName, '', false, false, slTbls);
        for i := 0 to slTbls.Count - 1 do
          ExportTable(slTbls[i]);
      finally
        slTbls.Free;
      end;
    end;procedure TKDatabaseToText.ImportTable(TableName : string);
    var
      i,j : integer;
      slIn, slValues : TStrings;
      MS1, MS2 : TMemoryStream;
      sz : integer;
    begin
      slIn := TStringList.Create;
      slValues := TStringList.Create;
      MS1 := TMemoryStream.Create;
      MS2 := TMemoryStream.Create;
      try
        MS1.Position := 0;
        FTable.TableName := TableName;
        FTable.Active := true;    ClearFileExt(TableName);
        slIn.LoadFromFile(FixPath(FWorkDir) + TableName + '.txt');
        if FileExists(FixPath(FWorkDir) + TableName + '.mem') then
          MS1.LoadFromFile(FixPath(FWorkDir) + TableName + '.mem');    for i := 0 to slIn.Count - 1 do
        begin
          FTable.Append;
          ComposeText(slIn[i], FDelimiter, '"', slValues);
          for j := 0 to slValues.Count - 1 do
          begin
            if not (FTable.Fields[j].DataType in [ftBlob, ftMemo, ftGraphic, ftFmtMemo,
                                                  ftParadoxOle, ftDBaseOle, ftTypedBinary]) then
              FTable.Fields[j].AsString := slValues[j]
            else begin
              sz := StrToInt(slValues[j]);
              if sz > 0 then
              begin
                MS2.CopyFrom(MS1,sz);
                MS2.Position := 0;
                (FTable.Fields[j] as TBlobField).LoadFromStream(MS2);
                MS2.Clear;
              end;
            end;
          end;
          FTable.Post;
        end;
        FTable.Active := false;
      finally
        MS1.Free;
        MS2.Free;
        slValues.Free;
        slIn.Free;
      end;
    end;procedure TKDatabaseToText.ImportDatabase;
    var
      slTbls : TStrings;
      i : integer;
    begin
      slTbls := TStringList.Create;
      try
        Session.GetTableNames(FDatabaseName, '', false, false, slTbls);
        for i := 0 to slTbls.Count - 1 do
          ImportTable(slTbls[i]);
      finally
        slTbls.Free;
      end;
    end;
    end.
      

  3.   

    to yqh and shang_yan, 源表和目的表分别在两个库里啊,用一条sql语句怎么弄?to wangzh(独孤求问), adodataset里有个method可以直接把表存在文件里,也可以从文件里取回到adodataset,但是只到dataset为止,我不知道怎么样才能把数据库里的表真正地更新。
    也是考虑到老兄说的问题,才不想一条一条地做循环的。
      

  4.   

    sql里有一个子句IN....
    如:
    select * from Student in 'class.mdb'
    上述语句就是从class.mdb中的student表中操作的。
      

  5.   

    另,不知你做的项目对安全要求是否高,如不高,倒不必考虑得wangzh(独孤求问)那么复杂。如果要求高,你完全可以将目的数据库文件备份一个,再行更新或新增记录。这样做简单(我看着那么长的代码就晕。)。
      

  6.   

    shang_yan, 谢谢,明白你的意思了,我马上就试但是还是想明白tadodataset的savetofile和LoadFromFile怎么用Tense(何必), 什么叫"通用的字段备份"?麻烦再详细点
      

  7.   

    savetofile和loadfromfile,你是想用于blob字段吗?
    搜索一下以前的旧帖或是看《delphi5开发人员指南》(你不会没有这本书吧?!),有例子。