2

日付範囲の預金オブジェクトを見つけるための私の非常に単純なクエリでは、次のようになります。

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

    def allUnprocessedDeposits = Deposit.executeQuery(sqlQuery)

DepositDateがendDateStringと等しい行は返されません。(?!?)たとえば、すべてのd.depositDate行を同じ日付に更新し、その日付をendDateStringとして指定すると、行は返されません。

grails2.0.3とMySql5.1を使用しています。

答えを持っている人に感謝します。これは非常に単純なようですが、厄介なことに失敗します。

4

3 に答える 3

3

DateTimeフィールドに1日を指定すると、mySQLは深夜を想定するため、深夜以降の時刻が含まれるものは結果に含まれません。日付<[終了日+1]と言った方がいいでしょう

于 2012-07-20T19:24:26.887 に答える
2

ところで、パラメータを使用してクエリを使用する必要があります。より安全です。

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

def allUnprocessedDeposits = Deposit.executeQuery(sqlQuery,[endDate:endDateVariable])
于 2012-07-20T19:34:06.640 に答える
2

あなたが提供した情報を考えると、最も可能性の高い説明は、depositDate列がDATETIMEまたはTIMESTAMPとして定義されているということです。これらのデータ型は、日付に加えて時間値(1秒までの解像度)を格納することに注意してください。例えば

'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列の述語の場合、「日」を取得する通常のパターンは、特定の日の深夜から翌日の深夜までの範囲スキャンを実行することです。確認したいのは、列が翌日の深夜よりも少ないかどうかです。

'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'

あなたの場合、あなたはすでに「終了日」の値を持っているので、最も簡単な変更は単にクエリテキストを変更することです。

渡す日付値に1日を追加し、比較演算子をから<=に変更するだけ<です。(ここでは、日付部分のみを指定し、時間部分をデフォルトで深夜に設定できると想定しています。)

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

DATEこのパターンは、、DATETIMEおよびで同様に機能するため、このパターンをお勧めしTIMESTAMPます。

(注:このパターンを好むもう1つの理由は、より細かい解像度の「特定の時点」の値で機能するためです(たとえば、Microsoft SQL Server DATETIMEは、精度が3ミリ秒で、<= 23:59.59のチェックを実行します)。結局不十分です。)

コードは、引数の値が日付のみであること、または時刻コンポーネントが深夜の日付であることを確認できますが、引数をaaでラップすることにより、SQLクエリにこれを実行させるのは簡単です。CAST( AS DATE)

注:関数内で列参照をラップすることは避けたいと思います。d.depositDateこれは、MySQLがインデックス範囲スキャン操作を実行する機能を無効にするためです(述語を満たすため)。


注:SQLインジェクションの脆弱性に関する通常の警告はすべてここに適用されます。引数の値がユーザーによって指定されている場合は、バインドパラメーターを使用するか、指定された....値をエスケープする必要があります。

悪意のあるユーザーが次のような値を提供するとどうなるかを考えてみてください。

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

どのステートメントがデータベースに渡されるかを検討してください。このような攻撃を阻止するために、これに対処するためのいくつかのアプローチがあります。

于 2012-07-20T20:16:38.170 に答える