当另一个字段数据不存在时清除一个字段

Posted

技术标签:

【中文标题】当另一个字段数据不存在时清除一个字段【英文标题】:Clear a field when another field data doesn't exist 【发布时间】:2017-08-27 18:09:01 【问题描述】:

我有一个名为“refFile”的字段,其中可能有也可能没有路径描述。

我需要遍历整个数据库并检查“refFile”中定义的路径是否仍然存在。

使用 Delphi (Pascal) 这需要很多很多分钟

bigDB.First;
while not(bigDB.EOF) do
begin 
  if Trim(bigDB.FieldByName('refFile').AsString) > '' then
  begin
    if not(FileExists(bigDB.FieldByName('refFile').AsString)) then
    begin
      bigDB.Edit;
      bigDB.FieldByName('refFile').AsString:='';
      bigDB.Post;
    end;
  end;
  bigDB.Next;
end;   

我如何在 SQL 中做到这一点?

谢谢。

【问题讨论】:

您使用的组件是什么? FireDAC、ADO、dbExpress..?首先要改进的是缓存字段引用(摆脱重复地按名称询问字段)。接下来仅取决于,所有文件都在同一目录下吗?或者任何驱动器上的任何地方?我的意思是,是否值得为此操作构建文件树?接下来可能是在不移动光标的情况下对数据集进行快速迭代。因此,例如检查数据集中的内容,例如,您是否没有在此数据集中存储和获取 blob。 为什么您实际上需要“提前”了解这些信息?文件存在可以经常改变.. 【参考方案1】:

您无法在 SQLLite 中检查路径的有效性,但您可以过滤路径中包含某些内容的记录并减少要检查的行列表。

您可以对该字段的记录进行排序(如果您有索引)并仅检查您之前未检查的路径。

您也可以使用线程在后台执行此长时间操作。只需使用 TThread.Createanonymousthread(procedure begin end).Start;

【讨论】:

最好的解决方案是过滤SQL中的记录(order + where),在Delphi中只检查以前没有检查过的路径。使用线程许可做后台工作,不要冻结应用程序。 @Victoria - 没错。我的经验是,如果您偏离问题并尝试解决 实际 问题,那么问题就会丢失,提问者(即使对于新手来说也是如此)会产生这样的印象,即您必须解决没有被问到的问题.我的观点是,我们应该鼓励提出更好的问题。 @Victoria - FWIW,我希望您不会考虑放弃 SO,因为我认为您通过输入和 cmets 带来了很多价值。 @Victoria:“FWIW,我希望你考虑不要放弃 SO” 我也是,我认为你在这里的贡献是无价的。 @Victoria:顺便说一句,我认为这个 q 和所有 cmets 只是表明,不充分的问题产生的热量多于光线。所以,我做了我希望更多人首先做的事情,即投票关闭,因为在它的上下文中,q 不够清楚,无法正确回答。【参考方案2】:

您无法在普通的 SQLLite 查询中检查文件是否存在。您可以使用UDF (User defined function) 来做到这一点,但它会稍微复杂一些,并且需要一些其他编程语言的技能(请注意,在这种情况下,您的文件应该可以从服务器访问,否则它将无法工作)。

如果您正在寻找更简单的解决方案,我认为您可以通过减少查询产生的记录数并改进您的 Delphi 代码来加快程序速度更高效。

选择 SQL:

使用length 和trim 函数可以减少Delphi 代码要验证的记录数。

select refFile 
from myTable
where (refFile is not null) and (length(trim(refFile)) > 0)

德尔福:

只拨打一次TDataSet.FieldByName。

尝试使用TDataSet.DisableControls和TDataSet.EnableControls(这样一些数据集的组件会更快,即使数据集组件没有链接到任何控件)。

var
  Fld : TField;
begin
  BigDB.DisableControls();
  try
    Fld := BigDB.FieldByName('refFile');

    BigDB.First;
    while not(BigDB.Eof) do
    begin
      if not(FileExists(Fld.AsString)) then
      begin
        BigDB.Edit;
        Fld.AsString := '';
        BigDB.Post;
      end;
      BigDB.Next;
    end;
  finally
    BigDB.EnableControls();
  end;

此外,您可以考虑以下其他优化:

如果refFile 字段多次包含相同的值,您可以按refFile 字段对查询进行排序并更改Delphi 代码以便只验证每个文件名一次。 (您可以通过存储FileExists 函数的最后一个值和结果来做到这一点)。 您可以使用TThread 类异步运行您的代码。这样您的应用程序就不会死机,而且速度会更快。

【讨论】:

想一想,通常数据库引擎甚至不会在客户端运行。 UDF 如何帮助过滤服务器端的客户端文件?虽然我怀疑这是否会成为您投反对票的原因,但看起来投反对票的人天生就已经越界了。 @SertacAkyuz:你说得对,我认为文件也可以从服务器访问是理所当然的。我通过指定这个事实更新了答案的第一部分。 你也可以在Delphi中注册UDF。这是关于导入一些 C 函数。您的客户端库只需要为打开的数据库提供句柄。 @exd - 谢谢。另请注意,客户端必须通过共享存储路径。 IE。如果数据库服务器不在同一台机器上,“c:\..something”对服务器没有任何意义。【参考方案3】:

例如使用 FireDAC,创建用户定义的函数非常容易。如果您正在使用它,请尝试类似的方法。它可以节省一些时间,因为引擎不需要将结果集获取到客户端应用程序:

uses
  FireDAC.Phys.SQLiteWrapper;

type
  TForm1 = class(TForm)
    Button1: TButton;
    FDQuery1: TFDQuery;
    FDConnection1: TFDConnection;
    FDGUIxWaitCursor1: TFDGUIxWaitCursor;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    FValidator: TSQLiteFunction;
    procedure ValidateFile(AFunc: TSQLiteFunctionData; AInputs: TSQLiteInputs;
      AOutput: TSQLiteOutput; var AUserData: TObject);
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FDConnection1.Open;

  FValidator := TSQLiteFunction.Create((TObject(FDConnection1.CliObj) as TSQLiteDatabase).Lib);
  FValidator.Args := 1;
  FValidator.Name := 'FileExists';
  FValidator.OnCalculate := ValidateFile;
  FValidator.InstallAll;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FDQuery1.SQL.Text :=
    'UPDATE MyTable SET FileName = NULL WHERE ' +
    'FileName IS NOT NULL AND NOT FileExists(FileName)';
  FDQuery1.ExecSQL;
end;

procedure TForm1.ValidateFile(AFunc: TSQLiteFunctionData; AInputs: TSQLiteInputs;
  AOutput: TSQLiteOutput; var AUserData: TObject);
begin
  AOutput.AsBoolean := FileExists(AInputs[0].AsString);
end;

或者干脆删除TFDSQLiteFunction组件,用函数名称填写FunctionName属性,编写类似于上面的OnCalculate事件处理程序,并通过设置Active属性启用组件。

【讨论】:

纯属推测,但我猜这会产生额外的减慢效果,因为假设数据库服务器位于不同的盒子上,对于每条记录,客户端都需要额外的往返。 @Sertac,我假设只在本地使用(抱歉,这篇文章是对使用 FireDAC 的猜测,所以我没有提到远程机器使用的可能性)。通过本地使用,您可能会获得一些加速,因为将整个文件名结果集获取到应用程序、检查是否存在并仅更新不存在的文件元组应该比 UDF 回调更昂贵。

以上是关于当另一个字段数据不存在时清除一个字段的主要内容,如果未能解决你的问题,请参考以下文章

因为该组节的条件字段不存在或无效所以无法打印

mysql查找字段在一个集合里存不存在

JPA怎么判断一个字段是不是存在?

where一个字段中不存在某个字符,怎么写mysql判断语句

当架构中不存在字段时,如何防止 django 出错?

php随机生成数据库中不存在、不重复数字