从RosterResource表中获取UserID

时间:2013-02-12 03:14:50

标签: sql sql-server-2008 tsql

我有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,但规则相当简单: 如果日期和ResourceID在SpecialRoster中,则UserID取自SpecialRoster 如果没有,资源的UserID和日期的RosterDay取自当时的名册当前

基本上,我需要将ResourceID,通过Roster或SpecialRoster中的UserID映射到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

1 个答案:

答案 0 :(得分: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和指定的任何其他表之间的连接。如果有一个,你只是忘了提及它,如果你需要任何帮助,请在脚本中加入必要的条件,请告诉我。