SQLite ExecuteReader --> DataTable.Load --> 格式异常 (日期时间)

19

我尝试读取一个样例Northwind sqlite数据库,但在一些包含日期时间的表格上出现错误。这是数据库的问题还是我的System.Data.SQLite的问题?异常信息类似于:“该字符串不是有效的DateTime”。

http://system.data.sqlite.org/

当然,我可以通过正确转换日期时间来自己读取数据,但这不如通过简单的dt.Load()读取数据高效。
        SQLiteCommand dbCommand = myConnector.CreateCommand();
        dbCommand.CommandText = "SELECT * FROM " + tablename;

        SQLiteDataReader executeReader = dbCommand.ExecuteReader(CommandBehavior.SingleResult);
        DataTable dt = new DataTable();
        dt.Load(executeReader); // <-- FormatException

"System.DateTimeParse.ParseExactMultiple(String s, String[] formats, DateTimeFormatInfo dtfi, DateTimeStyles style) at System.DateTime.ParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style) at System.Data.SQLite.SQLiteConvert.ToDateTime(String dateText, SQLiteDateFormats format, DateTimeKind kind) in c:\dev\sqlite\dotnet\System.Data.SQLite\SQLiteConvert.cs: line 322."
我需要一个优秀的帮手来改进当前的代码。

只是提出一个想法...通常这种类型的东西都隐藏在某个地方(也许是触发器中)...也许日志记录机制格式化日期时出现了错误?我敢打赌问题不在于将查询转换为DataTable,而是其他事情正在发生。 - Paul
请问您能告诉我表中有问题的DateTime列的格式吗? - HatSoft
样例数据库为:http://download.vive.net/Northwind.zip,表名为‘ORDERS’。根据SQLite数据库浏览器显示,有问题的列的类型为‘timestamp’。 - masterchris_99
+1 for这个问题,我在谷歌上找不到答案。只是阅读文档并思考,我解决了这个问题。 - Leandro Bardelli
你解决了我的答案所提出的问题吗?如果你解决了,请接受它。如果没有,请留下评论。 - Leandro Bardelli
3个回答

14

是的,我也遇到了同样的问题,并找到了解决方法。

首先,您需要知道为什么会出现这种情况。

http://www.sqlite.org/datatype3.html

**

SQLite没有专门用于存储日期和/或时间的存储类。相反,SQLite内置的日期和时间函数可以将日期和时间存储为TEXT、REAL或INTEGER值:

**

TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC. 

应用程序可以选择以任何格式存储日期和时间,并使用内置的日期和时间函数自由地在格式之间进行转换。

有关更多日期/时间函数,请参见此页面: http://www.sqlite.org/lang_datefunc.html

解决方案:

只需使用 datetime 函数将您的字段转换为有效的 .NET datatable 格式即可。您可以使用上面链接中的任何一个函数,在我的情况下,我选择了:

SELECT datetime(field) as field FROM table

提示1 如果您的查询涉及视图,并且无法操作数据库,则需要创建不同的视图或其他类似的东西,因为问题在于数据库端,正如我之前所解释的那样,这时您会遇到一些麻烦。因此,第一种解决方案是在加载数据表之前替换数据表的列(有点“肮脏”的工作)。或者您可以在文本字段上使用Unix时间戳或任何所需的时间戳。 但我认为最好的解决方案是从您的视图中在应用程序中创建查询:

SELECT datetime(field) as field FROM view

提示2

您还可以尝试使用SQLite管理员并在检查格式之前使用日期时间函数。

提示3

请注意全球化文化的影响,如果更改了文化,则可能会出现问题。尽量让您的软件仅适用于一种文化,并按您想要的方式显示它,而不是文化想要的方式。例如,在我的国家,我们通常使用此格式:dd/MM/yy,这很痛苦,就像小数点上的点(我们使用逗号)。

提示4

如果您正在使用向导定义的连接来处理某些报告、实体或类似的内容,请确保检查所需的转换格式。例如,我使用最常见且不会产生问题的方式:ISO8601。

SQLite - Add Connection


谢谢。但目前我还没有找到方法。我是一个数据库查看器,对数据库一无所知。默认的日期时间格式是8601。当我执行executeReader.GetString(3)时,我的表中会出现**"7/4/1996 12:00:00 AM"**。使用executeReader.GetDateTime(3)会导致FormatException异常。 - masterchris_99
我的意思是你的领域名称是什么?在你的代码中,你放置了“SELECT * FROM tablename”。尝试将此查询更改为“SELECT field1, field2, field3, field4, datatime(field), field6等从表中选择”。即使在应用程序中执行SELECT *也不是一个好主意。 - Leandro Bardelli
顺便提一下,您指定的日期时间不符合 ISO 标准。 - Leandro Bardelli
1
我并没有完全解决这个问题。但是在构建select-string时,我有一个小的变通方法,即读取所有列及其类型。问题在于我对数据库一无所知。 - masterchris_99
哦,那是另一个与问题无关的问题,但您可以执行“select * from scheme table”来了解所有信息,就像系统表一样。 - Leandro Bardelli
显示剩余2条评论

6
你尝试使用SQLiteDataAdapter来实现吗?
SQLiteDataAdapter da = new SQLiteDataAdapter(dbCommand);
da.Fill(dt);

也许它的操作方式相同,但尝试一下并不会有坏处 ;)


1

查看此文章关于SQLite和DateTime存储,标题为Storing DateTimes。


谢谢,但这对我没有帮助。这是我情况的进一步说明。但我不存储任何数据,我只想读取它。 - masterchris_99
你需要DateTime列吗?与其使用SELECT *,你可以限制列并省略DateTime值。这听起来像是数据格式问题。 - mgnoonan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接