1

在最初为客户手动编写多个报表作为 MVC 3 (EF4) 项目的一部分后,我决定在 Microsoft 报表服务(SQL Server 2008 上的 SSRS 2008)中编写报表要容易得多。对于我的大多数报告,这已被证明是轻而易举的事,甚至不必为我的大多数报告编写 SQL 过程(基于模型的 BIDS 中的语义查询)。

然而,由于其输入参数的性质以及最初是在返回列表而不是 LINQ 查询的函数中计算的,一份报告仍然令人生畏。目标是返回 people 表中在日期 a 和日期 b 之间的任何一天(由报告请求者输入的变量)内的所有忙于 x% 的人。此忙碌级别信息仅存在于 Job 表中,该表包含有关分配给哪个人员、作业的开始和结束日期以及任务级别的信息。结果,我原来的 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 为 = 那某人,则该作业在某人的日程表中

所以......因为我现在在 SSRS 2008 工作,我正在寻找有关如何从相同的输入参数在 SSRS 中获得这些相同结果的指导。一些我目前不知道的语义查询技巧?带有临时表或表变量的 SQL 存储过程?某种数据处理扩展?任何有关解决此类问题的最佳方法的信息将不胜感激。

让我知道是否需要其他信息/代码。

编辑:目前正在使用几乎复制我原始函数结构的游标和临时表的解决方案。但是由于游标的复杂性和低效性,这绝对不是理想的,因此建议/替代方案会有所帮助。

编辑:找到了一个解决方案,绝对不是最有效的。如果有人有更快的方法,将改变接受的答案。

4

3 回答 3

1

很抱歉,过了一段时间才回复您。我不认为有一种方法可以绕过使用 WHILE 循环来遍历这些日子,因为这样可以为您提供与用户输入范围进行比较所需的个别日子。我认为这个查询应该有助于提高速度,因为它不使用任何游标。我在 WHILE 循环中添加了逻辑,所以你只循环一次,结果就是你的临时表。变量名称可能有点不同,您可能会将 <= 切换为 < 或其他东西,但主要逻辑就在那里。

查询包括开始日期和结束日期,并设置为包括分配小于或等于用户输入的任何人。我希望它可以帮助你:

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

您的问题与 SSRS 无关。您只需要构建查询以提供 SSRS 上的数据集。我不关心数据如何到达数据源、查询、过程、临时表、魔术,就报告而言,它只关心字段名称。

因此,如果您无法将 linq 查询转换为 T-SQL 查询,我建议您在数据库上运行跟踪,从应用程序执行 linq 查询(然后您将在跟踪中看到 T-SQL),复制它并粘贴在报告的数据源上。

于 2012-05-01T16:22:10.393 回答
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 回答