【问题标题】:SQLite query to get the closest datetimeSQLite 查询以获取最近的日期时间
【发布时间】:2015-09-10 22:49:29
【问题描述】:

我正在尝试编写一条 SQLite 语句以从用户输入(来自 WPF 日期选择器)中获取最接近的日期时间。我有一个表 IRquote(rateId, quoteDateAndTime, quoteValue)。

例如,如果用户输入 10/01/2000 并且数据库只存储了 08/01/2000、07/01/2000 和 14/01/2000 的修复,它将返回 08/01/2000,是最接近 2000 年 10 月 1 日的日期。

当然,我希望它不仅适用于日期,还适用于时间。

我尝试使用此查询,但它返回日期最远的行,而不是最接近的行:

SELECT quoteValue FROM IRquote 
WHERE rateId = '" + pRefIndexTicker + "'
ORDER BY abs(datetime(quoteDateAndTime) - datetime('" + DateTimeSQLite(pFixingDate) + "')) ASC
LIMIT 1;

请注意,我有一个函数 DateTimeSQLite 将用户输入转换为正确的格式。

我不明白为什么这不起作用。 我怎么能做到?感谢您的帮助

【问题讨论】:

  • 你从哪里得到这个用户输入?数据存储在哪里?
  • 我不确定执行此操作的所有 SQL 命令,但我怀疑必须有某种方法来区分输入与存储的值,从中得出一个数值,然后按此排序值(ORDER BY),并获取第一条记录(TOP 1)。 (可以选择在排序前转换为绝对值,以防您想要任一方向的最近时间。)
  • @BerndLinde 我编辑了我的问题以添加更多详细信息。大卫我会用你提出的方法再试一次。感谢您的帮助

标签: sql sqlite datetime


【解决方案1】:

如果您可以确定时间/日期查询的上限和下限,则另一个有用的解决方案是使用 BETWEEN 运算符。我最近在link 中遇到了这个解决方案。这是我在名为 t 的时间列上使用的应用程序(更改日期列和日期函数的代码并不困难):

select *
from myTable 
where t BETWEEN '09:35:00' and '09:45:00' 
order by ABS(strftime('%s',t) -  strftime('%s','09:40:00')) asc 
limit 1

另外,我必须更正我对上述帖子的评论。我尝试简单检查@BerndLinde、@ypercubeᵀᴹ 和我提出的这 3 种方法的速度。我的 PC 中有大约 500 个表,每个表有 150 行,中等硬件。结果是:

  1. 解决方案 1(使用 strftime)大约需要 12 秒。
  2. 将列 t 的索引添加到解决方案 1 可将速度提高 30% 左右,大约需要 8 秒。使用时间索引(t)我没有遇到任何改进。
  3. 解决方案 2 的速度也比解决方案 1 提高了大约 30%,大约需要 8 秒
  4. 最后,解决方案 3 改进了大约 50%,大约需要 5.5 秒。添加列 t 的索引会带来更多改进,大约需要 4.8 秒。时间索引 (t) 在此解决方案中没有影响。

注意:我是一个简单的程序员,这是一个简单的 .NET 代码测试。真正的性能测试必须考虑更专业的方面,我不知道。在从数据库中查询和读取之后,我的代码中也有一些计算。此外,正如@ypercubeᵀᴹ 所述,此结果不适用于大量数据。

【讨论】:

    【解决方案2】:

    如果表很大,并且在 datetime 列上有索引,这将使用索引来获取最近的 2 行(高于和低于提供的值)并且效率更高:

    select * 
    from
      ( select * 
        from 
        ( select t.ID, t.Price, t.PriceDate
          from Test t
          where t.PriceDate <= datetime('2015-06-23 10:00:00') 
          order by t.PriceDate desc
          limit 1
        ) d
      union all
        select * from
        ( select t.ID, t.Price, t.PriceDate
          from Test t
          where t.PriceDate > datetime('2015-06-23 10:00:00') 
          order by t.PriceDate asc
          limit 1
        ) a
      ) x
    order by abs(julianday('2015-06-23 10:00:00') - julianday(PriceDate))
    limit 1 ;
    

    SQLfiddle 测试。

    【讨论】:

    • 我用 500 个表和每个大约 150 行(实际上是时间列而不是日期时间列)测试了您的解决方案。对我来说,@BerndLinde 的解决方案要快 40% 左右。我测试了各种索引:on column、on time(column)、on strftime('%s',column),它们都没有任何性能提升。
    • 150 行就是这么小的一张表,那么有多大区别呢?两个查询都在毫秒内运行吗?
    【解决方案3】:

    要获得最接近的日期,您需要使用 strftime('%s', datetime) SQLite 函数。

    使用thisexample/demo,您将获得最接近给定日期的日期。
    请注意,日期2015-06-25 10:00:00 是用户选择的输入日期时间。

    select t.ID, t.Price, t.PriceDate,
           abs(strftime('%s','2015-06-25 10:00:00') - strftime('%s', t.PriceDate)) as 'ClosestDate'
      from Test t
     order by abs(strftime('%s','2015-06-25 10:00:00') - strftime('%s', PriceDate))
     limit 1;
    

    SQL解释:
    我们使用strftime('%s') - strftime('%s') 来计算两个日期之间的差异(以秒为单位)(注意:它必须是“%s”,而不是“%S”)。由于这可以是正数或负数,我们还需要使用 abs 函数将其全部设为正数,以确保我们的 order by 和后续的 limit 1 部分正常工作。

    【讨论】:

    • 效率极低,将日期时间转换为字符串。
    • @ypercube SQLite 将 DateTime 存储为字符串,因此实际上没有发生转换。 SQLite 中没有 DateTime 类型
    • 我添加了一个查询的答案,该查询可以使用列上的索引(thnx 作为小提琴,我也使用了它;)
    • strftime('%s', t.PriceDate) 顺便进行了转换。在列上使用函数(strftime、abs)会使任何索引都无法用于查询。
    • 我必须写 'order by ClosestDate' 才能为我工作;否则很好,谢谢。
    猜你喜欢
    • 2017-10-02
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 2017-06-13
    • 1970-01-01
    • 1970-01-01
    • 2015-02-08
    • 1970-01-01
    相关资源
    最近更新 更多