1

当初、顧客向けの MVC 3 (EF4) プロジェクトの一環としていくつかのレポートを手動で作成した後、Microsoft レポート サービス (SQL Server 2008 上の SSRS 2008) でレポートを作成する方がはるかに簡単であると判断しました。私のレポートのほとんどで、これは簡単であることが証明されており、ほとんどのレポートで SQL proc を記述する必要さえありません (モデルに基づく BIDS のセマンティック クエリ)。

ただし、1 つのレポートは、入力パラメーターの性質上、元は LINQ クエリではなくリストを返す関数で計算されているため、困難なままです。目標は、日付 a から日付 b までの範囲 (レポート要求者によって入力された変数) の任意の日に x パーセント未満の忙しさである人物テーブル内のすべての人を返すことです。このビジー レベル情報は、担当者、ジョブの開始日と終了日、およびそのタスク レベルに関する情報を含むジョブ テーブルにのみ存在します。その結果、私の元の C# 関数は、ほとんど次のことを行います (疑似コード)。

given startDateRange a, stopDateRange b, busyLevel x
{
for each person in people:
   List returnPeople = new List()
   create array consisting of days from a to b
   for each job in jobs:
      for each intersecting date of DateRange and job dateRange:
         add task level of job to array
   for each day in array:
      if array[day] < x
         returnPeople.Add(person)
         break;
return returnPeople
}

関連する部分のテーブル構造:

People Table:
-PersonID (PK)
-other stuff...

Jobs Table:
-JobID (PK)
-StartDate
-StopDate
-Allocation
-AssignedPersonID (FK to People Table)

ご覧のとおり、そのジョブの AssignedPersonID が = that someone である場合、そのジョブは誰かのスケジュールに従っています

だから...私は現在SSRS 2008で作業しているので、同じ入力パラメーターからSSRSでこれらの同じ結果を取得する方法についてのガイダンスを探しています。私が現在気付いていないセマンティッククエリのトリックはありますか? 一時テーブルまたはテーブル変数を使用したSQLストアドプロシージャ? ある種のデータ処理拡張機能ですか? この種の問題への最善のアプローチについての情報は大歓迎です。

追加情報/コードが必要な場合はお知らせください。

編集:現在、カーソルと一時テーブルを使用して、元の関数の構造をほぼコピーするソリューションに取り組んでいます。これは間違いなく理想的ではありませんが、カーソルの複雑さと非効率的な性質のため、アドバイス/代替手段が役立ちます.

編集:解決策が見つかりましたが、間違いなく最も効率的ではありません。誰かが非常に高速な方法を持っている場合、受け入れられた回答を変更します。

4

3 に答える 3

1

申し訳ありませんが、ご連絡に時間がかかりました。ユーザーの入力範囲と比較するために必要な個々の日が得られるため、WHILEループで日をループする必要を回避する方法はないと思います。ただし、このクエリはカーソルを使用しないため、速度が多少向上すると思います。WHILE ループ内にロジックを追加したので、ループは 1 回だけで、結果として一時テーブルが作成されます。変数名は少し異なるかもしれませんし、<= を < などに切り替えるかもしれませんが、主なロジックはそこにあります。

クエリには開始日と終了日が含まれており、割り当てがユーザーの入力と同じかそれ以下のユーザーを含めるように設定されています。お役に立てば幸いです:

DECLARE @startDate datetime, @endDate datetime, @maxAllocation float, @dayCounter datetime

DECLARE @PeopleList TABLE (PersonId int, PersonName varchar(50))

SET @dayCounter = @startDate
WHILE @dayCounter <= @endDate
BEGIN
    INSERT INTO @PeopleList SELECT P.PersonId, P.PersonName FROM People P INNER JOIN Jobs J ON P.PersonId = J.AssignedPersonId
       WHERE J.StartDate <= @dayCounter AND J.StopDate >= @dayCounter
       GROUP BY P.PersonId, P.PersonName
       HAVING SUM(J.Allocation) <= @maxAllocation
    SET @dayCounter = DATEADD(DAY, 1, @dayCounter)
END

SELECT DISTINCT PersonId, PersonName FROM @PeopleList
于 2012-10-13T21:51:56.423 に答える
0

一時テーブルとネストされたカーソルの組み合わせで、TSQLストアドプロシージャを使用することになりました。おそらく最も効率的な解決策ではありませんが、うまくいけば、同じ問題を抱えている他の人を助けるでしょう。誰かがより効率的な解決策を投稿した場合、私は受け入れられた答えを変更します。それは私が最初に求めていたものです。

 DECLARE @PeopleList TABLE(
                                          PersonID CHAR(15)
                                          )
      DECLARE @PersonValue CHAR(10)
      --Local busyList table with all dates in desired range
            DECLARE @DateValue DATETIME
            DECLARE @TotalAllocation FLOAT
            DECLARE @BusyList TABLE(
                                                DateInRange DATETIME,
                                                AllocationForDate FLOAT
                                                )
            DECLARE @dayCounter DATETIME
            SET @dayCounter = @startDate
            INSERT INTO @BusyList VALUES (@startDate, 0)
            WHILE @dayCounter<@endDate
            BEGIN
                  SET @dayCounter = @dayCounter + 1
                  INSERT INTO @BusyList VALUES (@dayCounter, 0)
            END

      DECLARE currentUser CURSOR LOCAL FAST_FORWARD FOR
      SELECT PersonID FROM [People]

      OPEN currentPerson
      FETCH NEXT FROM currentPerson INTO @PersonValue
      WHILE (@@FETCH_STATUS = 0)
            BEGIN
            DECLARE currentDay CURSOR LOCAL FAST_FORWARD FOR
            SELECT DateInRange FROM @BusyList

            OPEN currentDay
            SET @TotalAllocation = NULL
            UPDATE @BusyList SET AllocationForDate = 0
            FETCH NEXT FROM currentDay INTO @DateValue
            WHILE (@@FETCH_STATUS = 0)
                  BEGIN
                        SET @TotalAllocation = (SELECT SUM(TaskLevel) FROM Job WHERE AssignedPersonID = @PersonValue AND @DateValue BETWEEN Opportunity.StartDate AND Job.EndDate)
                        UPDATE @BusyList
                        SET AllocationForDate = @TotalAllocation WHERE (DateInRange = @DateValue)
                        FETCH NEXT FROM currentDay INTO @DateValue
                  END
            CLOSE currentDay
            DEALLOCATE currentDay
            IF EXISTS(SELECT * FROM @BusyList WHERE AllocationForDate <= @allocation OR AllocationForDate IS NULL)
                BEGIN
                INSERT INTO @PersonList VALUES (@PersonValue)
                END
            PRINT @PersonValue
            FETCH NEXT FROM currentUser INTO @PersonValue
            END

      SELECT * FROM [People] WHERE EXISTS (SELECT * FROM @PersonList Where [@PersonList].PersonID = [Person].PersonID)

      CLOSE currentPerson
      DEALLOCATE currentPerson
于 2012-05-04T19:30:49.403 に答える
0

あなたの問題はSSRSとは関係ありません。SSRS でデータ セットをフィードするためのクエリを作成するだけです。レポートに関する限り、データがデータソース、クエリ、プロシージャ、一時テーブル、マジックにどのように到達するかは問題ではありません。フィールド名だけを気にします。

したがって、linq クエリを T-SQL クエリに変換できない場合は、データベースでトレースを実行し、アプリケーションから linq クエリを実行して (トレースに T-SQL が表示されます)、それをコピーして、レポートのデータソースに貼り付けます。

于 2012-05-01T16:22:10.393 に答える