0

日付列が nvarchar 型として保存され、日付形式がdd/mm/yyyy(英国式) であるデータベースがあります。2 つの日付の間に投稿されたデータを検索するために選択クエリを実行しようとしています。

クエリは次のとおりです。

SELECT * FROM table 
  WHERE CONVERT(datetime,postdate,103) BETWEEN ? AND ?

フィールドを日時に変換しましたが、クエリを実行しようとするとエラーが発生します

java.lang.Exception: com.microsoft.sqlserver.jdbc.SQLServerException:
nvarchar データ型から datetime データ型への変換により、範囲外の値が発生しました

isDate クエリを実行すると:

SELECT * FROM table WHERE ISDATE(postdate)=0

日付のある行18/02/2013が表示されます。私が間違っていなければ、これは18が月と見なされていることを意味します。

基本的にフィールドを有効な日付に変換し、日付を比較するにはどうすればよいですか?

4

2 に答える 2

3

最初の問題は、日付を文字列列に格納していることです。DATEまたはを使用しないのはなぜDATETIMEですか? d/m/y 形式を維持するためにこれを行っている場合は、それをやめてください。フォーマットはプレゼンテーション層の責任であり、ストレージに影響を与えるべきではありません。また、なぜ使用しているのNVARCHARですか?Unicode を必要とする日付リテラルでは、どのような記号が予想されますか?

次は、適切な検証が行われておらず、列に不適切なデータが含まれていることです。この不良データは次のように識別できます。

SET DATEFORMAT DMY;

SELECT * FROM dbo.table
  WHERE ISDATE(postdate) = 0;

NULLここで、クエリが 0 行を返すまで、データが何であるかがわかったら更新するか、それらの行を に設定して、そのデータを修正します。

明らかに D/M/Y 形式ではない 11/13/2013 のようなデータがある可能性があることに注意してください。この場合、有効に見えるが 06/09を入力したユーザーが行ったデータもある可能性があることに注意してください。 /2013 は 6 月 9 日または 9 月 6 日を意味しますか? どうすれば確信できますか?

この問題が明日再び発生するのを防ぐ最も安全な方法は、新しい列を追加し、データを移動し、古い列を削除し、すべてのレイヤーで文字列の使用を停止することです。

ALTER TABLE dbo.table
  ADD d DATE;

UPDATE dbo.table 
  SET d = CONVERT(DATETIME, postdate, 103);

ALTER TABLE dbo.table
  DROP COLUMN postdate;

EXEC sp_rename N'dbo.table.d', N'postdate', N'COLUMN';

次のように、このスワッピングをすべて行わなくても、インラインで実行できる場合があります。

SET DATEFORMAT DMY; -- the key you missed in your attempt I think
ALTER TABLE dbo.table ALTER COLUMN postdate DATE;

列自体を修正できない場合は、少なくともこの列にチェック制約と検証を追加して、明日不良データが戻ってこないようにすることを検討してください。例えば:

ALTER TABLE dbo.table
  ADD CONSTRAINT prevent_bad_dates
  CHECK (CONVERT(DATE, postdate, 103) >= '19000101');

挿入を実行するストアド プロシージャに varchar パラメータを使用すると仮定すると、挿入前の検証:

ALTER PROCEDURE dbo.whatever
  @postdate NVARCHAR(10), -- assuming here
  @other_params...
AS
BEGIN
  SET NOCOUNT ON;
  SET DATEFORMAT DMY;

  IF ISDATE(@postdate) = 0
  BEGIN
    RAISERROR('Incorrect format for date: %s.', 11, 1, @postdate);
    RETURN;
  END

  ... perform insert...
END

これでも06/09/2013、ユーザーが入力したのが6 月 9 日か 9 月 6 日かを理解するのに役立ちません。そのため、フリーハンドのアドホック エントリをユーザーから遠ざけて、カレンダー コントロールや日付ピッカーなどを使用するように強制することをお勧めします。そうすれば、フォーマットを完全に制御できます。文字列リテラルを SQL Server に送信する必要がある場合、最も安全な形式はYYYYMMDD. BETWEENまた、無制限の範囲の代わりに使用する場合の潜在的な問題に注意する必要があります。次の投稿をお読みください。

于 2013-03-26T11:09:07.660 に答える
-1

データベースから日付を取得すると、日付が java.sql.date 形式で取得されます。

これを java.util.date に変換する必要があります。

次のコードを使用して実行できます

java.util.Date utilDate = new java.util.Date(SQLDate.getTime());

それを試してみてください、それは行われます!!

于 2013-03-26T11:07:59.730 に答える