1

これが私のコードです:

        #region Validate and prepare parameters
        if (month > 12)
        {
            throw new ArgumentException("Value of 'month' could not be greater than 12.");
        }

        int yearEnd = year;
        int monthEnd = 0;
        if (month != 12)
        {
            monthEnd = month + 1;
        }
        else
        {
            monthEnd = 1;
            yearEnd = year + 1;
        }
        #endregion

        MyModelDataContext context = new MyModelDataContext();

        string sql =
            @"select SUM(ORDERQTY * MULTIPLIER) AS VOL_USD
                from Executions with (nolock)
                where TRANSACTTIME >= '{0}-{1}-01 00:00:00'
                    and TRANSACTTIME < '{2}-{3}-01 00:00:00'
                    and MTCONTEXT in (5,6)
                    and ORDERQTY > 0
                    AND SOURCE = 'INTMT'
                    and LEFT(SYMBOL, 3) = 'USD'";

        decimal usd___Sum = context.ExecuteQuery<decimal>(sql, year, month, yearEnd, monthEnd).First();

私は例外を取得しています:

文字列から日時を変換する際に変換に失敗しました。

ExecuteQueryメソッドを呼び出すとき。year の値は 2013 で、month の値は 9 です。何が間違っていますか?

前もって感謝します。

4

2 に答える 2

3

文字列を日付と比較しているため、データベースは適切な形式を「推測」する必要があります。使用する形式は ISO 形式ではないため、データベースは照合に一致する形式を使用すると想定します。LATIN1 などを使用していると思います。

整数を渡す代わりに、それらを文字列に変換します。たとえばTRANSACTTIME >= '{0}-{1}-01 00:00:00'、日付を渡すだけです。

 var startDate=new DateTime(year,month,1);
 var endDate=new DateTime(yearEnd,monthEnd,1);

 string sql =
        @"select SUM(ORDERQTY * MULTIPLIER) AS VOL_USD
            from Executions with (nolock)
            where TRANSACTTIME >= {0}
                and TRANSACTTIME < {1}
                and MTCONTEXT in (5,6)
                and ORDERQTY > 0
                AND SOURCE = 'INTMT'
                and LEFT(SYMBOL, 3) = 'USD'";

decimal usd___Sum = context.ExecuteQuery<decimal>(sql, startDate,endDate).First();

アップデート

Ovidiu が示唆するように、パラメーター置換は文字列内では機能しないため、@p0、@p1 パラメーターの値を指定しても、'@p0-@p1-01' は変更されません。各部分を連結して、文字列の外側に日付を作成する必要があります。

SQL Server 2012 では、DATETIMEFROMPARTSを使用した別のオプションがあります。その部分から日付を作成できます。たとえば、次のようになります。

 string sql =
        @"select SUM(ORDERQTY * MULTIPLIER) AS VOL_USD
            from Executions with (nolock)
            where TRANSACTTIME >= DATETIMEFROMPARTS({0},{1},1,0,0,0,0)
            ..."

実際の日付を渡すことは依然として好ましいですが

于 2013-11-07T09:07:56.097 に答える
1

問題はcontext.ExecuteQuery、クエリをデータベースに送信する方法です。と同様に {0} などの引数を使用しますがstring.Format、実際にはこれらの引数を文字列値に置き換えるのではなく、パラメーターとして DB に送信します。少し混乱します。

SQL Profiler を開くと、クエリが次のように変換されることがわかります。

exec sp_executesql 
    N'select SUM(ORDERQTY * MULTIPLIER) AS VOL_USD
    from Executions with (nolock)
    where TRANSACTTIME >= ''@p0-@p1-01 00:00:00''
    and TRANSACTTIME < ''@p2-@p3-01 00:00:00'''
,N'@p0 int,@p1 int,@p2 int,@p3 int'
,@p0=2013,@p1=9,@p2=2013,@p3=10

パラメータ@p0が一重引用符内に表示され、文字列として解釈され"@p0"、実際の値に置き換えられないため、SQL で例外がスローされます2013。だから、'2013-09-01 00:00:00'あなたが終わる代わりに'@p0-@p1-01 00:00:00'

文字列の代わりにオブジェクトを送信DateTimeする方が良い解決策です

where TRANSACTTIME >= {0} and and TRANSACTTIME < {1}
...
context.ExecuteQuery<decimal>(sql, new DateTime(year, month, 1), new DateTime(yearEnd, monthEnd, 1))

ただし、現在の構造を維持したい場合は、引数がSQLの{0}パラメーターになることに注意して、次のようなものを使用する必要があります@p0

where TRANSACTTIME >= convert(datetime, {0} + '-' + {1} + '-01 00:00:00')
  and TRANSACTTIME < convert(datetime, {2} + '-' + {3} + '-01 00:00:00')
...
context.ExecuteQuery<decimal>(sql, year.ToString(), month.ToString(), yearEnd.ToString(), monthEnd.ToString())
于 2013-11-07T10:02:09.203 に答える