2015-07-02 38 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

相關問題