web-dev-qa-db-ja.com

SQLServerで動的クエリを使用して日時を操作する

やあみんな、私は日時を保持する変数を使用したい動的クエリを使用しています。クエリを実行すると、日時を文字列から変換できないと表示されます。その変数をvarchar(max)にキャストすると、次のようになります。 datetimeではなく文字列として送信するので、クエリをどのように実行する必要がありますか。

以下は、実行しようとしているSQLクエリです。

SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity, 
CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE FROM '+@TABLE+' B
WHERE B.TillDate BETWEEN CONVERT(VARCHAR(10),'+@FROMDATE+', 101) and 
CONVERT(VARCHAR(10), DATEADD(DD,1,'+@TODATE+'), 101)'

EXEC SP_EXECUTESQL @SQL1

ここに @fromdateおよび@todateは、異なる一時テーブルからのdatetimeタイプです。これらの変数に格納されます。

ここで、このクエリをどのように実行する必要がありますか。すぐに返信してください...

アッバスエレクトリックワーラに感謝します。

9
Abbas

日付を引用する必要があります。

SET @SQL1 = 
   'SELECT B.FacId, 
           B.FacName, 
           B.BookCode, 
           B.BookName, 
           B.Quantity, 
           CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE 
           FROM '+@TABLE+' B 
           WHERE B.TillDate BETWEEN ''' + CONVERT(VARCHAR(10),@FROMDATE, 101) + ''' and ''' + CONVERT(VARCHAR(10),DATEADD(DD,1,@TODATE), 101) + ''''
28
bleeeah

このようにパラメータ値を連結しないでください。最善の解決策は、sp_executesqlでパラメーター化されたクエリを使用することです。

_DECLARE @sql nvarchar(4000)

select @sql = N'
  SELECT B.FacId 
       , B.FacName
       , B.BookCode
       , B.BookName
       , B.Quantity
       , CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE 
    FROM ' + quotename(@TABLE) + N' B
   WHERE B.TillDate BETWEEN cast(floor(cast(@fromDate as float)) as datetime)
                        AND cast(floor(cast(@toDate as float)) as datetime)'

EXEC sp_executesql @sql, N'@fromDate datetime, @toDate datetime', @FROMDATE, @TODATE
_

Sp_executesqlについて注意すべき点は次のとおりです。

  • パラメータはNVARCHAR値です
  • 3番目と4番目のパラメーターは元のデータ型を保持し、varcharに変換する必要はありません。これにより、SQLインジェクションが再び保護され、動的SQLで非常に一般的な引用符のスープを防ぐため、クエリが読みやすくなります。

クエリにいくつかの追加の変更が適用されました。

  • テーブル名は、オブジェクト名へのSQLインジェクションから保護するQUOTENAME()関数でラップされます。
  • 日時変数の日付部分を削除する方法は、あまり最適ではありません。 convert(,,101)を実行することはコストのかかる操作であり、キャストを使用してフロートし、その値のフロアを取得することで実行できます。
7
Filip De Vos

私はこれがうまくいくかもしれないと思います:

 DECLARE @tempdate datetime
 SET tempdate =DATEADD(DD,1,@TODATE)
 SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity,'''+  cast     (B.TillDate as VARCHAR(50))+''' AS TILLDATE FROM '+@TABLE+' B WHERE B.TillDate BETWEEN '''+cast(@FROMDATE as VARCHAR(50))+''' and  '''+cast(@tempdate as VARCHAR(50))'''

 EXEC SP_EXECUTESQL @SQL1 
2
MaryamAyd

変数の定義を確認したいのですが、@ FROMDATEと@TODATEが日時であり、文字列連結ステートメントで使用しているためだと思います。したがって、次の方法で修正できます。

SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity, CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE FROM '+@TABLE+' B WHERE B.TillDate BETWEEN CONVERT(VARCHAR(10),'+CAST(@FROMDATE as varchar(15))+', 101) and CONVERT(VARCHAR(10), DATEADD(DD,1,'+CAST(@TODATE as varchar(15))+'), 101)'

ただし、より良い解決策は次のとおりです。

  1. 動的SQLはまったく使用しないでください。おそらく、@ TABLEはそれほど変化せず、ビューなどに結合できます。
  2. パラメータをsp_executeSQLに直接渡して、タイプを保持します。

SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity, B.TillDate AS TILLDATE FROM '+@TABLE+' B WHERE B.TillDate BETWEEN @inFROMDATE and @inTODATE'

EXEC SP_EXECUTESQL @SQL1,'@inFROMDATE datetime, @inTODATE',@inFromDate = @FROMDATE, @inTODATE = @TODate

2
Joel Mansford

この例を実行して、コードに適合させます。 (3つの連続した一重引用符はありません)

Declare @FromDATE  datetime
;Declare @ToDATE datetime
;set @FromDATE = getdate() 
;set @ToDATE = @FromDATE 

;Print 'WHERE TillDate BETWEEN ' + char(39) + CONVERT(VARCHAR(10),@FromDATE, 101) 
+ char(39) + ' and ' + char(39) + CONVERT(VARCHAR(10),@ToDATE, 101) + char(39)
0
Gustavo

これを試して:

declare @sql1 varchar(max)
declare @table sysname
declare @FROMDATE datetime
declare @TODATE datetime

set @table = 'MyTable'
set @FROMDATE = GETDATE()
set @ToDATE = GETDATE()


SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity, 
CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE FROM '+@TABLE+' B
WHERE B.TillDate BETWEEN CONVERT(Datetime,''' + CONVERT(VARCHAR(10),@FROMDATE, 101) 
+ ''', 101) and CONVERT(DATETIME,'''+ CONVERT(VARCHAR(10), DATEADD(DD,1,@TODATE), 101) + ''', 101)'


print @sql1

しかし、二重変換を避けるために、ジョエル・マンスフォードの答えを見てください。

0
bernd_k

これは遅いですが、誰かを助けるかもしれません

あなたが必要とするのはあなたの日付の周りの引用です、あなたはすでにあなたの答えを得ました。

以下は、私が通常クエリに入力するものの例です。

'(CONVERT(DATETIME,CONVERT(varchar,Gd.CreatedDate),106) <= CONVERT(DATETIME,'''+CONVERT(varchar, @EndDate ) +''',106))'

@EndDateのタイプはDatetimeであることに注意してください。

0
Hardik