2015-07-02 36 views
-2

我有以下情况:有一个表格,其中一列是日期时间字符串。我想要做的是了解本表中提及哪些年份,即:我想阅读“日期 - 时间”列中的所有行,并查看哪些年份与我的“已提及年份列表”不同;如果一个给定的行还没有添加一年,我将这一年添加到我的列表中,最后我会提到所有年份。如何快速捕获SQLite数据库特定列中的不同数据?

现在很自然,我知道如何在一个非常昂贵的算法中做到这一点,这将是上述文本的字面实现。我想知道的是,如果有一种快速的方式,也许更“原生”的做这样的查询 - 你可以想象如果我试图按照上面所述完全实现一个算法,我会得到巨大的处理器成本。

有什么更好的点子?

详细信息:我用C++/Qt编程,表格可能很大(如10000行或更多)。

回答

2

您可以选择min(日期 - 时间)和max(日期 - 时间),并从中获得年份,然后遍历其间的所有年份,检查期间是否存在具有日期时间的记录有问题的一年。不知道它会更快,但可能值得一试。

或者您可以选择不同的X,其中X是返回日期的年份部分的函数。这可能是最原始,最干净的方式;我害怕日期操作函数倾向于特定于sql平台,所以我不确定sqlite的语法。

看起来它可能是

select distinct strftime('%Y', date-time) as Year 
0

我不熟悉SqlLite细节,但它是接近ANSI在某些方面:一个快速的方式不同的计算值,诸如,就是

select strftime('%Y',datetime) 
from TABLE 
group by strftime('%Y',datetime) 

通过在sqlserver中使用不带集合函数的分组将返回不同的单列。

如果SQLite是不是有利于,你也可以选择其他列的数量,到几年限制不同

1

为了获得最佳性能,需要有对datetime字符串列一个合适的索引。我会建议(不一定建议)一种避免一些其他查询模式潜在性能问题的方法。

我建议的方法是利用多个查询,每个查询返回一个包含新的年份值的单行。 (我假定将有只有几个不同的年份值,很多行对于给定的一年。)

让我们假设我现有的几年列表包含2011年,2013年和2014年

以下描述了我将运行的查询的顺序,利用现有的值作为我运行的查询中的谓词。基本的想法是,我只需要在给定的一年中找到一行......不需要读取全部的行。

我需要现有的年份列表才能顺利。我会从最低值开始,然后运行一个查询,获得该年之前的最早日期。我希望能够最有效地使用索引的查询以及Sqllite中的优化。

我在现有列表中的最早年份值是'2011'。我推说进入查询......我的第一个镜头会是这样的:

select dt from t where dt < '2011-01-01' 
    order by dt limit 1 

如果我没有得到行了,我知道,2011年是最早的一年。

如果我确实得到了一排,我知道这是一个“新”年。我会将前四个字符作为年份,并将其添加到我的列表中。我会比较2011年的这一年的价值,如果差距超过一个,我会检查下一个最低年份。

例如,如果该查询返回与“2008”的开始日期,下一个查询我运行与2008年后的最低日期时间与上年行检查,但在2011年之前

select dt from t where dt < '2011-01-01' 
    and dt >= datetime('2008-01-01','+1 years') 
    order by dt limit 1 

如果我没有再回来,我知道在2011年之前没有更多的“新”年值。我的下一个查询将使用2011年作为下限,并且我现有列表中的下一年值将作为上限,并且再次重复相同的查询。

如果我得到行回来了,日期时间,随着2009年开始我要补充2009年进入我的列表,我的下一个查询酷似上面的一个,但与2009年到位2008 ...

select dt from t where dt < '2011-01-01' 
    and dt >= datetime('2009-01-01','+1 years') 
    order by dt limit 1 

同样地,如果我没有得到一排,那时我才知道有没有更多的新的一年在2011年之前

所以,现在2011年是我的下界,并于次年在我现有的列表上限。所以,同样的查询再次,只有改变了一年的文字...

select dt from t where dt < '2013-01-01' 
    and dt >= datetime('2011-01-01','+1 years') 
    order by dt limit 1 

如果我得到一排,这是一个新的一年里要添加到我的名单。这是我下一个查询的新下界。如果没有行,那么最后一个查询的上限是新的下限。

为了优化模式,我会跳过运行一个我知道不会返回一行的查询。当我已经有2013年和2014年在我的名单,我的查询将是这种模式的......

select dt from t where dt < '2014-01-01' 
    and dt >= datetime('2013-01-01','+1 years') 
    order by dt limit 1 

,但我们知道,有同时满足这两个条件的任何行。一行不能有小于2014并且大于或等于2014的dt值,这是不可能的条件,所以我们可以跳过执行它。

当我到达列表中的最后一个值时,我将删除上限条件......我不在乎下一个查询是否返回2015年,2017年或2032年...无论是最近一年我在我的名单中。

select dt from t where 
     dt >= datetime('2014-01-01','+1 years') 
    order by dt limit 1 

如果我收回一行,将该年添加到列表中,并将其用作我的下一个下限。并重复,直到我没有排队回来。

这确实运行了几个查询,但它们应该非常有效。在Hugh Jass表格中,这些可能是查找新年值最有效的查询。

如果这种模式发生故障,那么当我们需要运行大量查询时,当我们需要检查很多“空白”时。

这种模式最糟糕的情况将是以数字结尾的数百个现有年份值。每年的价值都有差距,我们必须检查它们之间的差距。

但是这种模式的最好情况是连续年值的长列表。如果没有找到新的年份值,我们最多可以运行两个查询。一个检查较早的一年(未找到),另一个检查较晚的一年(未找到)。


同样,这种方法的性能完全取决于其对dt一个适当的索引和查询计划,有效地使用该索引的。

+1

我们不一定需要使用'datetime'函数向日期文本添加一年,我们可以轻松地在客户端上处理该日期,并将年份值加1。 (我使用datetime函数来说明我们使用的是我们检索的年份值,或者是在我们的列表中。这还假定“日期时间字符串”列以一致的格式存储,并且前导日期部分位于格式为“'yyyy-mm-dd'” – spencer7593

+1

如果我们从一个现有的年份值列表开始,它是* empty *,我们的第一个查询在dt列上将没有谓词(条件),只是最早得到 – spencer7593

+0

谢谢对于这个有趣的算法的仔细解释!顺便说一句,你的假设是正确的:虽然数据库可能用于说30年,但在大多数时间,我将有一个连续的同一年的条目列表(这将有相同的格式,'yyyy/MM/dd'。 – Momergil

相关问题