Delphi Firebird 时间戳字段的 DBGrid 日期格式
Delphi DBGrid date format for Firebird timestamp field
我将 Firebird 数据库的内容显示到 TDBgrid 中。数据库有一个 'TIMESTAMP' 数据类型字段,我想以 date/time 格式显示:
'YYYY/MM/DD HH:mm:ss'。 (现在显示为'YYMMDD HHmmss')
如何实现?
我试过这个:
procedure TDataModule1.IBQuery1AfterOpen(DataSet: TDataSet);
begin
TDateTimeField(IBQuery1.FieldByName('timestamp_')).DisplayFormat := 'YYYY/MM/DD HH:mm:ss';
end;
但这会在程序的其他部分造成一些副作用,因此它不是替代方案。例如,在 'IBQuery1.Open' 语句中,我在清除数据库的方法中收到“...timestamp_ not found...”调试器消息。
function TfrmLogger.db_events_clearall: integer;
begin
result := -1;
try
with datamodule1.IBQuery1 do begin
Close;
With SQL do begin
Clear;
Add('DELETE FROM MEVENTS')
end;
if not Prepared then
Prepare;
Open; //Exception here
Close;
Result := 1;
end;
except
on E: Exception do begin
ShowMessage(E.ClassName);
ShowMessage(E.Message);
Datamodule1.IBQuery1.close;
end;
end;
end;
我在尝试打开写入数据库的查询时收到相同的异常消息。
*编辑 >>
我把数据库修改清楚如下:
function TfrmLogger.db_events_clearall: integer;
var
IBQuery: TIBQuery;
IBTransaction: TIBTransaction;
DataSource: TDataSource;
begin
result := -1;
//Implicit local db objects creation
IBQuery := TIBQuery.Create(nil);
IBQuery.Database := datamodule1.IBdbCLEVENTS;
DataSource := TDataSource.Create(nil);
DataSource.DataSet := IBQuery;
IBTransaction := TIBTransaction.Create(nil);
IBTransaction.DefaultDatabase := datamodule1.IBdbCLEVENTS;
IBQuery.Transaction := IBTransaction;
try
with IBQuery do begin
SQL.Text := DELETE FROM MSTEVENTS;
ExecSQL;
IBTransaction.Commit;
result := 1;
end;
except
on E : Exception do
begin
ShowMessage(E.ClassName + ^M^J + E.Message);
IBTransaction.Rollback;
end;
end;
freeandnil(IBQuery);
freeandnil(DataSource);
freeandnil(IBTransaction);
end;
清除数据库后,我可以将记录加载到 dbgrid 中,好像数据库还没有更新。程序重启后可以看到所有记录都被删除了
整个function TfrmLogger.db_events_clearall
好像很可疑
- 您没有提供
SQL_DELETE_ROW
,但根据回答,这似乎不是 SELECT-请求返回 "resultset"。所以很可能它不应该是“.Open”的运行,而是“.Execute”或“.ExecSQL”或类似的东西。
更新。它被添加 SQL_DELETE_ROW = 'DELETE FROM MEVENTS';
证实了我之前和进一步的期望。几乎。常量名称建议您要删除一行,而查询文本说您删除所有行,我想知道这是正确的吗?..
此外,由于没有 "resultset" - .Exec....
之后 .Close
没有任何内容 - 但如果有这样的 [=,您可以检查 .RowsAffected
112=] 在 DBX 中,查看实际计划删除多少行。
此外,不,此函数不会删除行,它只会安排删除行。在处理 SQL 时,您确实必须投入时间和精力来学习 TRANSACTIONS,否则您很快就会被副作用淹没。
特别是,您必须在此处提交删除事务。为此,您要么必须显式创建、启动并绑定到 IBQuery
事务,要么找出 IBQuery1
和 .Commit;
它隐式使用了哪个事务。 .Rollback
例外。
是的,很无聊,诸如此类。你可能希望 IBX 足够聪明,偶尔为你做一次提交。但是,如果不通过事务隔离数据更改,您将很难重现来自各种 "race conditions".
的 "side effects"
示例
FieldDefs.Clear; // frankly, I do not quite recall if IBX has those, but probably it does.
Fields.Clear; // forget the customizations to the fields, and the fields as well
Open; // Make no Exception here
Close;
Halt; // << insert this line
Result := 1;
试试这个,我打赌你的 table 不会被清除,尽管查询是 "opened" 和 "closed" 没有错误。
整个With SQL do begin
怪物可以用单线SQL.Text := SQL_DELETE_ROW;
代替。了解 TStrings
class 在 Delphi 中的含义 - 它在 Delphi 图书馆的很多地方使用,因此了解此 class 服务将节省您很多时间和功能。
没有必要 Prepare
一次性查询,您执行后就忘记了。对不更改 SQL.Text
但仅更改参数的查询进行了准备,然后使用相同的文本但不同的值重新打开查询。
好吧,有时我确实使用(误用?)显式准备来确保库从服务器获取参数数据类型。但是在您的示例中,两者都没有。但是,您的代码不使用参数,并且您不使用许多相同的 neverchanging SQL.text
打开。因此,它变成了噪音,使打字时间更长,阅读更难。
尝试 ShowMessage(E.ClassName + ^M^J + E.Message)
或只是 Application.ShowException(E)
- 没有必要让两个停止模态 windows 而不是一个。
Datamodule1.IBQuery1.close;
- 这实际上是回滚事务的地方,而不是仅仅关闭无论如何都没有打开的查询。
现在,让两个(或更多?)SQL 请求抛出一个 Delphi 查询对象的想法本身就值得怀疑。您对查询进行自定义,例如修复 DisplayFormat
或设置字段的事件处理程序,那么该查询就非常值得持续自定义。您甚至可以在设计时设置 DisplayFormat
,为什么不呢。
争夺一个 TIBQuery
对象毫无意义 - 有多少就有多少。截至目前,您必须普遍而准确地推断出您程序的每个函数中 IBQuery1
内的文本。
这再次为未来的副作用创造了可能性。想象一下,你在某个地方做 function1; function2;
,后来你决定需要交换它们并做 function2; function1;
。你可以做到吗?但是,如果 function2
更改 IBQuery1.SQL.Text
并且 function1
取决于先前的文本怎么办?然后呢?
所以,基本上,对您的查询进行排序。应该有那些跨函数调用的查询,然后它们最好有一个专用的查询对象,不要过度使用不同的查询。并且应该有 "one time" 查询只在一个函数内部使用,从不在函数外部使用,例如 SQL_DELETE_ROW
- 如果小心使用,您可能会过度使用这些查询。但更好的办法是重新制作这些函数,使它们的查询成为局部变量,除了它们自己之外没有人可见。
PS。看来你被 IBX 库困住了,那么我建议你看看这个扩展 http://www.loginovprojects.ru/download.php?getfilename=uploads/other/ibxfbutils.zip
除其他外,它还提供通用 insert/delete 函数,这些函数会在内部创建和删除临时查询对象,因此您不必考虑它。
交易管理仍由您牢记和控制。
我将 Firebird 数据库的内容显示到 TDBgrid 中。数据库有一个 'TIMESTAMP' 数据类型字段,我想以 date/time 格式显示: 'YYYY/MM/DD HH:mm:ss'。 (现在显示为'YYMMDD HHmmss')
如何实现?
我试过这个:
procedure TDataModule1.IBQuery1AfterOpen(DataSet: TDataSet);
begin
TDateTimeField(IBQuery1.FieldByName('timestamp_')).DisplayFormat := 'YYYY/MM/DD HH:mm:ss';
end;
但这会在程序的其他部分造成一些副作用,因此它不是替代方案。例如,在 'IBQuery1.Open' 语句中,我在清除数据库的方法中收到“...timestamp_ not found...”调试器消息。
function TfrmLogger.db_events_clearall: integer;
begin
result := -1;
try
with datamodule1.IBQuery1 do begin
Close;
With SQL do begin
Clear;
Add('DELETE FROM MEVENTS')
end;
if not Prepared then
Prepare;
Open; //Exception here
Close;
Result := 1;
end;
except
on E: Exception do begin
ShowMessage(E.ClassName);
ShowMessage(E.Message);
Datamodule1.IBQuery1.close;
end;
end;
end;
我在尝试打开写入数据库的查询时收到相同的异常消息。
*编辑 >>
我把数据库修改清楚如下:
function TfrmLogger.db_events_clearall: integer;
var
IBQuery: TIBQuery;
IBTransaction: TIBTransaction;
DataSource: TDataSource;
begin
result := -1;
//Implicit local db objects creation
IBQuery := TIBQuery.Create(nil);
IBQuery.Database := datamodule1.IBdbCLEVENTS;
DataSource := TDataSource.Create(nil);
DataSource.DataSet := IBQuery;
IBTransaction := TIBTransaction.Create(nil);
IBTransaction.DefaultDatabase := datamodule1.IBdbCLEVENTS;
IBQuery.Transaction := IBTransaction;
try
with IBQuery do begin
SQL.Text := DELETE FROM MSTEVENTS;
ExecSQL;
IBTransaction.Commit;
result := 1;
end;
except
on E : Exception do
begin
ShowMessage(E.ClassName + ^M^J + E.Message);
IBTransaction.Rollback;
end;
end;
freeandnil(IBQuery);
freeandnil(DataSource);
freeandnil(IBTransaction);
end;
清除数据库后,我可以将记录加载到 dbgrid 中,好像数据库还没有更新。程序重启后可以看到所有记录都被删除了
整个function TfrmLogger.db_events_clearall
好像很可疑
- 您没有提供
SQL_DELETE_ROW
,但根据回答,这似乎不是 SELECT-请求返回 "resultset"。所以很可能它不应该是“.Open”的运行,而是“.Execute”或“.ExecSQL”或类似的东西。
更新。它被添加 SQL_DELETE_ROW = 'DELETE FROM MEVENTS';
证实了我之前和进一步的期望。几乎。常量名称建议您要删除一行,而查询文本说您删除所有行,我想知道这是正确的吗?..
此外,由于没有 "resultset" - .Exec....
之后 .Close
没有任何内容 - 但如果有这样的 [=,您可以检查 .RowsAffected
112=] 在 DBX 中,查看实际计划删除多少行。
此外,不,此函数不会删除行,它只会安排删除行。在处理 SQL 时,您确实必须投入时间和精力来学习 TRANSACTIONS,否则您很快就会被副作用淹没。
特别是,您必须在此处提交删除事务。为此,您要么必须显式创建、启动并绑定到 IBQuery
事务,要么找出 IBQuery1
和 .Commit;
它隐式使用了哪个事务。 .Rollback
例外。
是的,很无聊,诸如此类。你可能希望 IBX 足够聪明,偶尔为你做一次提交。但是,如果不通过事务隔离数据更改,您将很难重现来自各种 "race conditions".
的 "side effects"示例
FieldDefs.Clear; // frankly, I do not quite recall if IBX has those, but probably it does.
Fields.Clear; // forget the customizations to the fields, and the fields as well
Open; // Make no Exception here
Close;
Halt; // << insert this line
Result := 1;
试试这个,我打赌你的 table 不会被清除,尽管查询是 "opened" 和 "closed" 没有错误。
整个
With SQL do begin
怪物可以用单线SQL.Text := SQL_DELETE_ROW;
代替。了解TStrings
class 在 Delphi 中的含义 - 它在 Delphi 图书馆的很多地方使用,因此了解此 class 服务将节省您很多时间和功能。没有必要
Prepare
一次性查询,您执行后就忘记了。对不更改SQL.Text
但仅更改参数的查询进行了准备,然后使用相同的文本但不同的值重新打开查询。 好吧,有时我确实使用(误用?)显式准备来确保库从服务器获取参数数据类型。但是在您的示例中,两者都没有。但是,您的代码不使用参数,并且您不使用许多相同的 neverchangingSQL.text
打开。因此,它变成了噪音,使打字时间更长,阅读更难。尝试
ShowMessage(E.ClassName + ^M^J + E.Message)
或只是Application.ShowException(E)
- 没有必要让两个停止模态 windows 而不是一个。Datamodule1.IBQuery1.close;
- 这实际上是回滚事务的地方,而不是仅仅关闭无论如何都没有打开的查询。现在,让两个(或更多?)SQL 请求抛出一个 Delphi 查询对象的想法本身就值得怀疑。您对查询进行自定义,例如修复
DisplayFormat
或设置字段的事件处理程序,那么该查询就非常值得持续自定义。您甚至可以在设计时设置DisplayFormat
,为什么不呢。
争夺一个 TIBQuery
对象毫无意义 - 有多少就有多少。截至目前,您必须普遍而准确地推断出您程序的每个函数中 IBQuery1
内的文本。
这再次为未来的副作用创造了可能性。想象一下,你在某个地方做 function1; function2;
,后来你决定需要交换它们并做 function2; function1;
。你可以做到吗?但是,如果 function2
更改 IBQuery1.SQL.Text
并且 function1
取决于先前的文本怎么办?然后呢?
所以,基本上,对您的查询进行排序。应该有那些跨函数调用的查询,然后它们最好有一个专用的查询对象,不要过度使用不同的查询。并且应该有 "one time" 查询只在一个函数内部使用,从不在函数外部使用,例如 SQL_DELETE_ROW
- 如果小心使用,您可能会过度使用这些查询。但更好的办法是重新制作这些函数,使它们的查询成为局部变量,除了它们自己之外没有人可见。
PS。看来你被 IBX 库困住了,那么我建议你看看这个扩展 http://www.loginovprojects.ru/download.php?getfilename=uploads/other/ibxfbutils.zip 除其他外,它还提供通用 insert/delete 函数,这些函数会在内部创建和删除临时查询对象,因此您不必考虑它。
交易管理仍由您牢记和控制。