2012-07-20 59 views
2

在我的非常簡單的查詢發現存款對象的日期範圍:查詢未找到日期範圍內最後一天的行(使用<=)?

String sqlQuery ="select d from Deposit d where status in('PENDING', 'SKIPPED') and d.depositDate <= '${endDateString}'" 

    def allUnprocessedDeposits = Deposit.executeQuery(sqlQuery) 

沒有行endDateString其DEPOSITDATE等於被返回。 (?!?)例如,如果我將所有d.depositDate行更新爲相同日期,並將該日期作爲endDateString提供,則不會返回任何行。

使用Grails 2.0.3和MySQL 5.1 ...

由於與答案的人。這看起來很簡單,但令人煩惱地失敗。

回答

2

考慮您所提供的信息,最可能的解釋depositDate列被定義爲DATETIME或TIMESTAMP。請注意,除日期外,這些數據類型還會存儲時間值(分辨率降至一秒)。例如

'2012-07-20 11:35:46' 

比較一個DATETIME值所以一個DATE文字(沒有時間組件),例如,

'2012-07-20 11:35:46' <= '2012-07-20' 

等同於用文字與午夜的時間值的DATETIME一個比較:

'2012-07-20 11:35:46' <= '2012-07-20 00:00:00' 

這顯然會返回FALSE。這就是爲什麼你的查詢沒有返回你期望的行的最可能的解釋。


修復建議:

有關DATETIME和TIMESTAMP列謂詞,正常模式得到一個「天」是從一天的午夜做範圍掃描高達午夜次日。我們要檢查什麼是列是否大於次日午夜LESS:

'2012-07-20 11:35:46' < DATE_ADD('2012-07-20', INTERVAL 1 DAY) 

這相當於相較於21日午夜。

'2012-07-20 11:35:46' < '2012-07-21 00:00:00' 

在你的情況,因爲你已經有一個「結束日期」的值,最簡單的變化是簡單地更改查詢文本。

只需在您傳入的日期值中添加一天,然後將比較運算符從<=更改爲<。 (我這裏假設你是隻供應日期部分,並允許部分時間默認爲午夜。)

... d.depositDate < DATE_ADD('${endDateString}',INTERVAL 1 DAY)" 

我們更喜歡這種模式,因爲它同樣適用於DATEDATETIMETIMESTAMP。(注意:我們更喜歡這種模式的另一個原因是因爲它可以以更高分辨率的「時間點」值工作(例如,Microsoft SQL Server DATETIME,其精度可低至3毫秒,並且可以執行< = 23:59.59不足。)

您的代碼可以確保參數值僅爲日期,或者是具有午夜時間組件的日期,但通過SQL查詢執行此操作很容易將你的論點打包在aa中CAST( AS DATE)

注意:你想避免在任何函數中包裝列引用d.depositDate,因爲這會禁用MySQL的abil可以執行索引範圍掃描操作(以滿足謂詞)。


注:所有關於SQL注入漏洞通常的警告適用於這裏,如果參數值是由用戶提供的,你想要麼使用綁定的參數或逃避提供....值

考慮當惡意用戶提供如下值時會發生什麼:

2012-07-20'; DELETE FROM Deposit ; SELECT '1 

考慮將哪些語句傳遞到數據庫。處理這個問題有幾種方法來阻止這種攻擊。

+0

哇,這真棒,@ spencer7593!我忘記了時間部分,默認爲零。 (我曾嘗試挖掘這個答案,但沒有打神奇的搜索詞組合。)我也非常感謝包裝列引用的注意事項;我沒有意識到這一點,這是一個很好的提示。還要感謝關於漏洞的說明;幸運的是,輸入被控制。 – Alexx 2012-07-23 15:17:10

3

當你只給DateTime字段一天時,mySQL會假設午夜,所以午夜之後的任何事情都不會包含在你的結果中。你最好說日期< [結束日期+ 1]

2

BTW,你應該使用帶參數的查詢,這是更安全:

String sqlQuery ="select d from Deposit d where status in('PENDING', 'SKIPPED') and d.depositDate <= :endDate" 

def allUnprocessedDeposits = Deposit.executeQuery(sqlQuery,[endDate:endDateVariable]) 
+0

謝謝,盧卡斯!仍然是一個時髦的新手...在Java中有15年的時間,很難適應新的語法/技巧(沒有適當的指導)。 – Alexx 2012-07-23 15:18:14