【问题标题】:SQL table to delphi record using BCP使用 BCP 到 delphi 记录的 SQL 表
【发布时间】:2011-12-20 08:26:55
【问题描述】:

我有一个场景,我必须从 sql 表中导出大约 500,000 条记录的数据,以便在 Delphi 应用程序中使用。数据将被加载到打包记录中。有没有一种方法可以让我使用 BCP 写入数据文件,类似于将记录写入文件。

到目前为止,我正在使用此伪代码加载数据。

    // Assign the data file generated from BCP to the TextFile object.
    AssignFile(losDataFile, loslFileName);
    Reset(losDataFile);
    while not EOD(losDataFile) do
    begin
      // Read from the data file until we encounter the End of File
      ReadLn(losDataFile, loslDataString);

      // Use the string list comma text to strip the fields
      loclTempSlist.CommaText := loslDataString;

      // Load the record from the items of the string list.
      DummyRec.Name := loclTempSList[0];
      DummyRec.Mapped = loclTempSList[1] = 'Y';
    end;

为方便起见,我在下面列出了 Dummy rec 的类型

    TDummyRec = packed record
      Name : string[255];
      Mapped : Boolean;
    end;

所以,我的问题是,除了将数据导出到文本文件之外,是否可以将数据导出为二进制文件,以便我可以直接使用记录类型从文件中读取?

喜欢

   loclFileStream := TFileStream.Create('xxxxxx.dat', fmOpenRead or fmShareDenyNone);
   while loclFileStream.Position < loclFileStream.Size do
   begin
     // Read from the binary file
     loclFileStream.Read(losDummyData, SizeOf(TDummyRec));
     //-  -------- Do wat ever i want.
   end;

我没有太多使用 BCP 的经验。请帮我解决这个问题。

谢谢 终结者...

【问题讨论】:

  • 只是一个提示,不是回答:TFileStream.
  • 为什么不用Delphi直接访问SQL Server呢?
  • Jens.. 我提供的示例仅适用于 2 列,但在实际情况下,我有 140 列数据要加载。我尝试使用 TADOQuery 加载它们,但应用程序的 2GB 内存已用完。所以,我想到了这个替代方案......
  • @RahulW ADO 能够检索任意大小的数据,每行一行。我认为您正在将这些数据映射到内存中。

标签: sql delphi bcp


【解决方案1】:

在您的记录中,string[255] 将创建一个固定大小的 Ansi 字符串(即所谓的shortstring)。这种类型显然已被弃用,不应在您的代码中使用。

使用TFileStream 直接保存它会非常浪费空间(即使它可以工作)。每条记录将为每个名称存储 256 个字节。

并且使用string[255](即所谓的shortstring)将对字符串进行隐藏转换,以便大多数访问它。所以这不是最好的选择,恕我直言。

我的建议是使用我们的开源课程use a dynamic array then serialize / unserialize it。对于您的存储,您可以使用动态数组。适用于 Delphi 5 到 XE2。您将能够在记录中使用string

TDummyRec = packed record
  Name : string; // native Delphi string (no shortstring)
  Mapped : Boolean;
end;

在 OP 评论后编辑:

BCP 只是一个命令行工具,用于导出很多行一个 SQL 表。所以恕我直言,BCP 不是您的理想人选。

您似乎需要导入很多行来自一个 SQL 表。

在这种情况下:

  • 使用shortstring 在任何情况下都会浪费内存,因此与使用良好的string 相比,内存不足的速度会更快;
  • 您可以尝试我们的开源类来一一检索所有数据行,然后使用这些数据填充您的记录:请参阅SynDB classes - 它比 ADO 更轻;然后,您将能够逐一检索记录数据,然后使用我们的记录序列化功能创建一些二进制内容 - 或尝试像我们的 SynBigTable 这样的专用更快引擎;
  • Delphi代码in here - it is in french, but you can use google to translate ithere for fast bulk copy中有一些关于直接使用BCP使用的OleDB功能的文章;包含完整的源代码。

【讨论】:

  • 嗨 Arnaud,空间对我来说不是一个限制,使用固定记录大小读取数据会很容易,因为不推荐使用短字符串,也许我可以使用固定的 char 数组长度。但是,我的问题是,我可以使用 BCP 以固定的二进制格式写入数据,以便我可以立即从文件中读取记录....谢谢您的建议,但它没有回答我的问题。
  • @RahulW 查看我编辑的答案。我认为您以错误的方式使用 BCP(填充数据库更快,而不是从数据库中检索数据)。
【解决方案2】:

您想将 SQL 表读入记录,我不知道您为什么要使用古老的 AssignFile。

您应该真正为您的数据库使用 TADOQuery(或合适的变体)。
在其中放入一个合理的 SQL 查询;类似:

SELECT field1, field2, field3 FROM tablename WHERE .....

如有疑问,您可以使用:

SELECT * FROM tablename

这将从表中选择所有字段。

以下代码将遍历所有记录和所有字段,并将它们保存在变体中,并将​​其保存在 FileStream 中。

function NewFile(Filename: string): TFileStream;
begin
  Result:= TFileStream.Create(Filename, fmOpenWrite);
end;

function SaveQueryToFileStream(AFile: TFileStream; AQuery: TADOQuery): boolean;
const
  Success = true;
  Failure = false;
  UniqueFilePrefix = 'MyCustomFileTypeId';
  BufSize = 4096;
var
  Value: variant;
  Writer: TWriter;
  FieldCount: integer;
  c: integer;
  RowCount: integer;
begin
  Result:= Success;
  try
    if not(AQuery.Active) then AQuery.Open

    FieldCount:= AQuery.Fields.Count;
    Writer:= TWriter.Create(AFile, BufSize);
    try
      Writer.WriteString(UniqueFilePrefix)
      //Write the record info first
      Writer.WriteInteger(FieldCount);
      //Write the number of rows
      RowCount:= AQuery.RecordCount;
      WriteInteger(RowCount);
      AQuery.First;
      while not(AQuery.eof) do begin
        for c:= 0 to FieldCount -1 do begin
          Value:= AQuery.Fields[c].Value;
          Writer.WriteVariant(Value);
        end; {for c}
        AQuery.Next;
      end; {while}
    except 
      Result:= failure;
    end;
  finally
    Writer.Free;
  end;
end;

【讨论】:

    猜你喜欢
    • 2013-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-11
    相关资源
    最近更新 更多