TL;DR-SQLストアドプロシージャの関数インポートが間違ったデータを返しています。ストアドプロシージャを呼び出す他のすべてのメソッドは、正しいデータを返します。
SQL Server2008R2サーバーに次の署名を持つストアドプロシージャがあります
ALTER PROCEDURE [dbo].[GetCrashCountByTime]
@start_date datetime,
@end_date datetime,
@moving_avg bit = 0,
@issue_id int = null,
@granularity int -- Either 1, 2, 3, 4, or 5 for Minute, Hour, Day, Month, Year grouping
-- Other inputs removed for brevity
WITH RECOMPILE
AS
BEGIN
-- ...SQL goes here...
END
SQLからの呼び出し例は次のようになります。
DECLARE @return_value int
EXEC @return_value = [dbo].[GetResultsByTime]
@start_date = '2013-01-14',
@end_date = '2013-01-16',
@issue_id = 1637,
@granularity = 2 -- equivalent to grouping by Hour
SELECT 'Return Value' = @return_value
GO
time | count | avg
-----------------------------------------
2013-01-14 00:00:00.0000000 | 2 | 0
2013-01-14 01:00:00.0000000 | 1 | 0
2013-01-14 02:00:00.0000000 | 1 | 0
2013-01-14 03:00:00.0000000 | 1 | 0
...
重要なのは、@ Granularityパラメーターが、結果をグループ化する方法(分、時間、日、月、または年)を決定することです。たとえば、日付(3)を使用するように呼び出しを少し変更すると、(予想どおりに)異なる結果が得られます。
DECLARE @return_value int
EXEC @return_value = [dbo].[GetResultsByTime]
@start_date = '2013-01-14',
@end_date = '2013-01-16',
@issue_id = 1637,
@granularity = 3
SELECT 'Return Value' = @return_value
GO
time | count | avg
-----------------------------------------
2013-01-14 00:00:00.0000000 | 21 | 0
2013-01-15 00:00:00.0000000 | 80 | 0
2013-01-16 00:00:00.0000000 | 0 | 0
...
(今のところ平均を無視してください、それは無関係です)。
この方法でSQLから直接呼び出すと、関数が機能していることを確認しました。
このストアドプロシージャを使用して、Entity Frameworkプラグイン(EFバージョン4.0.0.0)を使用してMVCアプリケーションの一部のデータをグラフ化します。まず、データベースからの変更で.edmxファイルを更新しました。モデルエクスプローラーを開き、ウィザードを使用してGetResultsByTimeの関数インポートを追加し、新しい複合型GetResultsByTime_Resultを自動的に生成しました。ただし、生成された関数を使用すると、指定したものではなく、粒度の「日」を渡したかのように結果が得られます。例えば、
C#コードでSPを呼び出す:
var data = db.GetResultsByTime(param.StartDate, param.EndDate, param.IssueId, param.Granularity).ToList(); // param.Granularity is an Enum value, in this case GranularityType.Hour
// data has only 2 entries, instead of 24 or so as expected
サーバーエクスプローラーを使用してストアドプロシージャを実行すると、正しい結果が再び得られます。
Running [dbo].[GetCrashCountByTime] ( @start_date = 2013-01-14, @end_date = 2013-01-16, @issue_id = 1637, @granularity = 2 ).
day crash_count avg_count
------------------------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2013-01-14 00:00:00.0000000 2 0
2013-01-14 01:00:00.0000000 1 0
2013-01-14 02:00:00.0000000 1 0
誰かアイデアはありますか?ストアドプロシージャを定義するSELECTに@granularityを追加して、SQLで期待どおりの値を取得し、渡されたのと同じ値を常に返すようにしました。残りのデータは次のようになります。 3(日)で合格しましたが。
冗長性をお詫び申し上げます。重要な詳細を省略しないように注意したいと思います。
編集:マシューの提案で、私はStackExchangeMiniProfilerを含めることでプロファイリングをオンにしました。Webサイトからデータを要求した後、プロファイラーは生成されたSQLが次のとおりであることを示します。
ExecuteStoreCommands CreateFunctionObjectResult ExecuteFunction ExecuteFunction GetCrashCountByTime CrashesByDay
DECLARE @start_date DateTime2 = '2013-01-01T00:00:00',
@end_date DateTime2 = '2013-01-17T09:14:00',
@issue_id int = 1637,
@granularity int = 2
[dbo].[GetCrashCountByTime]
ここに示すように2に解決される「時間」を選択しました。
編集2:
平均を計算するかどうかを制御する別の入力変数@moving_avgビットがあります。したがって、ストアドプロシージャには次のようなセクションがあります。
CREATE PROCEDURE [dbo].[GetResultsByTime]
-- ...
@moving_avg bit = 0,
-- ...
IF @moving_avg = 0
BEGIN
-- Do calculation without average
END
ELSE
BEGIN
-- Calculate average
END
生成されたSQLを見ると、@moving_avgがnullに設定されていることがわかりました。nullまたは0をチェックするように手順を変更しました。
IF @moving_avg = 0 OR @moving_avg IS NULL
BEGIN
-- Do calculation without average
END
そして今、それは粒度の議論を「聞いている」ようです。
'Minute'粒度を使用しているときに見つけたエラーを修正します-ありがとうございました!