-1

我有 5 个表:位置、收费、资源、名册和 SpecialRoster。

CREATE TABLE Location(
LocationID int identity,
StartDate datetime,
DaysInRoster int)

CREATE TABLE Charge(
ChargeID int identity,
TotalAmount money,
ChargeDate datetime,
UserID int)

CREATE TABLE [Resource](
ResourceID int identity,
ResourceName varchar(100))

CREATE TABLE Roster(
RosterDay int,
ResourceID int,
StartDate datetime,
EndDate datetime,
UserID int)

CREATE TABLE SpecialRoster(
RosterDate datetime,
ResourceID int,
UserID int)

我需要构建一个报告,按 ResourceID 显示不同日期的 Charge.TotalAmount 总和。

Charge 只有一个 UserID,但规则相当简单:如果 date 和 ResourceID 在 SpecialRoster 中,则 UserID 取自 SpecialRoster 如果没有,则 Resource 的 UserID 和日期的 RosterDay 取自当时的 Roster时间

基本上,我需要通过 Roster 或 SpecialRoster 中的 UserID 将 ResourceID 映射到 Charge。

RosterDay 是花名册的当前日期,可以从位置计算,其中RosterDay = DateDiff(day, Location.RosterStartDate, GetDate()) % Location.DaysInRoster

即,整个名册在该地点的开始时间与名册期间的天数之差的模数。

我写了一个函数来做到这一点:

CREATE FUNCTION dbo.GetRosteredUser
(
@ResourceID int,
@Date datetime,
@LocationID int
)
RETURNS  int
AS
BEGIN

DECLARE @UserID int
DECLARE @RosterOffset int

Select @UserID = UserID from SpecialRoster Where ResourceID = @ResourceID and RosterDate = @Date 

If @UserID is NOT NULL 
    return @UserID
else
    Select @RosterOffset = DATEDIFF(day, StartDate, @Date) % DaysInRoster 
    from Location Where LocationID = @LocationID

    Select @UserID = UserID from Roster Where ResourceID = @ResourceID and RosterDay = @RosterOffset
    and ( @Date between StartDate and EndDate or @Date > StartDate and EndDate is NULL)
    return @UserID
END
GO

但是该功能不是很好,因为它很慢,并且只允许报告一次运行一天:

Select a.ResourceID, Name, a.UserID, Sum(c.TotalAmount ) as AmountCharged
from Charge  c 
left outer join (
Select ResourceID, Name, 
dbo.GetUserByResourceDate(ResourceID, '1/FEB/2013', 1) as UserID 
from [Resource]) a
on c.UserID = a.UserID 
Where ChargeDate between '1/FEB/2013' and '2/FEB/2013'
group by a.ResourceID, Name, a.UserID

有一个更好的方法吗?用户将希望运行它来比较一段时间内资源的生产力。例如:

Date         ResourceID Name    UserID   TotalAmount
01/FEB/2013  1          Sales1  22       $1024
02/FEB/2013  1          Sales1  11       $1454
03/FEB/2013  1          Sales1  14       $1900
04/FEB/2013  1          Sales1  23       $3045
4

1 回答 1

1

也许,这样的事情可能会有所帮助:

SELECT
  re.ResourceID,
  re.ResourceName,
  ch.UserID,
  AmountCharged = SUM(ch.TotalAmount)
FROM
  Location lo
  CROSS JOIN Charge ch
  CROSS APPLY (
    SELECT DATEDIFF(DAY, lo.StartDate, ch.ChargeDate) % lo.DaysInRoster
  ) x (RosterDay)
  INNER JOIN
    [Resource] re
    LEFT JOIN Roster ro
    ON
      ro.RosterDay = x.RosterDay
      AND ch.ChargeDate BETWEEN ro.StartDate
      AND ro.RecourceID = re.ResourceID
    LEFT JOIN SpecialRoster sr
    ON
      sr.RosterDate = ch.ChargeDate
      AND sr.RecourceID = re.ResourceID
  ON
    ch.UserID = ISNULL(sr.UserID, ro.UserID)
GROUP BY
  re.ResourceID,
  re.ResourceName,
  ch.UserID
WHERE
  lo.LocationID = @LocationID
  AND ch.ChargeDate BETWEEN ...
;

在上面的脚本中,假设所有日期时间值实际上只是日期。

此外,我有点惊讶地没有找到Location指定的任何其他表之间的连接。如果有一个并且您只是忘记提及它,请让我知道您是否需要任何帮助以将必要条件合并到脚本中。

于 2013-02-13T09:01:41.343 回答