为什么SQL语句会返回有序数据集?

时间:2018-02-13 20:07:44

标签: sql datetime sqlite

我编写了一个程序,使用SQL语句将事件记录到db文件中。每当我打开表格进行查看时,我都会根据ALARM的日期和时间以降序的方式专门请求数据集。它似乎只适用于表的一部分。我使用的是SQLite3,我的程序是用delphi或Pascal编写的。

这是SQL语句:

SELECT * 
FROM Alarms 
ORDER BY datetime(ALARMTIME) DESC

以下是该表的快照。注意红色箭头。警报的日期和时间不按降序排列。我不知道为什么会这样。

enter image description here

1 个答案:

答案 0 :(得分:3)

我不确定您是如何在数据库中创建日期/时间字符串的,因为问题中未提供该信息。但是,根据documentation for the datetime() functionMM/DD/YYYY HH:MM:SS xx的格式不是可接受的格式之一。实际上,如果在SQLite提示符下执行SELECT datetime('1/23/2018 01:40:00 PM'),则会得到NULL。然而,如果您使用可接受的格式,则不会:SELECT datetime('2018-01-23')给出'2018-01-23 00:00:00'

所以我认为解决方案是使用ALARMTIME来编写datetime('now')字段,这会产生datetime()接受的格式。如果您需要根据现有格式进行排序,则无法使用datetime()进行排序。您需要使用字符串函数重新格式化字段,以便将表格与(例如。,与here完成)进行字符串比较。

<小时/> OP在评论中指出ALARMTIME是使用以下Pascal代码设置的:

FieldByName('AlarmTime').AsDateTime := now;

无法保证Pascal将在此上下文中使用与SQLite的datetime()函数兼容的日期/时间字符串格式。因此,Pascal日期/时间格式化函数可用于创建SQLite datetime()更具体接受的格式。然后你会使用类似的东西:

FieldByName('AlarmTime').AsString := FormatDateTime('YYYY-MM-DD hh:nn:ss',now);

现在,这会将日期的默认视图更改为YYYY-MM-DD ...。如果你仍然希望你的表格视图显示MM/DD/YYYY...,那么你需要回到我之前关于在排序比较中处理字符串的评论,或者写一点视图格式化代码所以它以与内部存储的格式不同的格式显示,这是一种常见的视图/模型分离技术。

<小时/> 如果您可以将原始ALARMTIME格式写为MM/DD/YYYY,并确保使用零预填充(例如01/09/2018而不是1/9/2018),那么您可以使用SQLite的substr功能:

SELECT * FROM Alarms
    ORDER BY (substr(ALARMTIME,7,4)||substr(ALARMTIME,1,2)||substr(ALARMTIME,4,2)||substr(ALARMTIME,11)) DESC

您可以使用以下方式创建ALARMTIME

FieldByName('AlarmTime').AsString := FormatDateTime('dd-mm-yyyy hh:nn:ss', now);

<小时/> 上述解决方案相当通用。根据您使用的客户端库(您尚未指定),可能有另一种更合适的方法来解决问题。

例如,您不能SELECT * FROM Alarms ORDER BY ALARMTIME DESC并获得准确的排序,例如,即使12/1/2018 {@ 1}}在该排序顺序中2/1/2018之后也是如此2/1/2018时间较晚。这是因为2在ASCII整理顺序中跟随1

如果您需要保留当前的ALARMTIME字符串格式,而不是更改保存方式,这有点自由形式m/d/yyyy,其中日期或月份可以有一个或两个数字,如果您的客户端库在这方面不支持某些帮助程序,那么您将需要做一些工作才能对其进行排序。也许您唯一的另一种选择是使用自定义SQLite函数。它们用C语言编写,并与SQLite编译和链接。你必须找到一个已经写好的,或自己写的。