4

当社には、従業員または請負業者 (リソース) が働いた時間を入力する時間管理システムがあり、そのためのコストが導き出されます。履歴コストの表があります。

CREATE TABLE ResourceTimeTypeCost (
 ResourceCode VARCHAR(32),
 TimeTypeCode VARCHAR(32),
 EffectiveDate DATETIME,
 CostRate DECIMAL(12,2)
)

したがって、発効日を示す日付フィールドが 1 つあります。記録があれば

('ResourceA', 'Normal', '2012-04-30', 40.00)

そして、次のレコードを追加します

('ResourceA', 'Normal', '2012-05-04', 50.00) 

したがって、4 月 30 日から 5 月 3 日の間に入力された時間はすべて £40.00 になり、4 日の午前 0 時以降はすべて £50.00 になります。これは原則として理解できますが、このロジックを表現するクエリをどのように記述しますか?

私のタイムテーブルが以下のようになっていると仮定します

CREATE TABLE TimeEntered (
 ResourceCode VARCHAR(32),
 TimeTypeCode VARCHAR(32),
 ProjectCode VARCHAR(32),
 ActivityCode VARCHAR(32),
 TimeEnteredDate DATETIME,
 HoursWorked DECIMAL(12,2)
)

次のレコードを TimeEntered テーブルに挿入すると

('ResourceA','Normal','Project1','Management1','2012-04-30',7.5)
('ResourceA','Normal','Project1','Management1','2012-05-01',7.5)
('ResourceA','Normal','Project1','Management1','2012-05-02',7.5)
('ResourceA','Normal','Project1','Management1','2012-05-03',7.5)
('ResourceA','Normal','Project1','Management1','2012-05-04',7.5)
('ResourceA','Normal','Project1','Management1','2012-05-07',7.5)
('ResourceA','Normal','Project1','Management1','2012-05-08',7.5)

リソースごとの総コストを返すクエリを取得したい

上記の場合、「ResourceA」、(4 * 7.5 * 40) + (3 * 7.5 * 50) = 2325.00 になります。

誰でもサンプル SQL クエリを提供できますか? この例が TimeType を使用していないことはわかっています (つまり、常に「通常」です) が、これがどのように処理されるかを確認したいと思います。

データベースの構造を変更できません。よろしくお願いします

4

3 に答える 3

3

あなたが持っているのは、ある人が言うように、ゆっくりと変化するディメンションであるコスト テーブルです。まず、コスト テーブルの有効日と終了日を設定すると役立ちます。これは、次の方法で自己結合とグループ化を行うことで取得できます。

with costs as
    (select c.ResourceCode, c.EffectiveDate as effdate,
            dateadd(day, -1, min(c1.EffectiveDate)) as endDate,
            datediff(day, c.EffectiveDate, c1.EffectiveDate) - 1 as Span
     from ResourceTimeTypeCost c left outer join
          ResourceTimeTypeCost c1
     group by c.ResourceCode, c.EffectiveDate
    )

テーブル構造を変更できないと言っていますが、ゆっくりと変化するディメンションがある場合は、有効日と終了日を設定することをお勧めします。

これで、次のように TimeEntered でこの情報を使用できます。

select te.*, c.CostRate * te.HoursWorked as dayCost
from TimeEntered te join
     Costs c
     on te.ResouceCode = c.ResourceCode and
        te.TimeEntered between c.EffDate and c.EndDate

特定の時間範囲のリソース別に要約すると、完全なクエリは次のようになります。

 with costs as
    (select c.ResourceCode, c.EffectiveDate as effdate,
            dateadd(day, -1, min(c1.EffectiveDate)) as endDate,
            datediff(day, c.EffectiveDate, c1.EffectiveDate) - 1 as Span
     from ResourceTimeTypeCost c left outer join
          ResourceTimeTypeCost c1
     group by c.ResourceCode, c.EffectiveDate
    ),
      te as
    (select te.*, c.CostRate * te.HoursWorked as dayCost
     from TimeEntered te join
          Costs c
          on te.ResouceCode = c.ResourceCode and
             te.TimeEntered between c.EffDate and c.EndDate
    )
select te.ResourceCode, sum(dayCost)
from te
where te.TimeEntered >= <date1> and te.TimeEntered < <date2>
于 2012-05-17T10:55:19.387 に答える
3
IF OBJECT_ID ('tempdb..#ResourceTimeTypeCost') IS NOT NULL DROP TABLE #ResourceTimeTypeCost
CREATE TABLE #ResourceTimeTypeCost (  ResourceCode VARCHAR(32),  TimeTypeCode VARCHAR(32),  EffectiveDate DATETIME,  CostRate DECIMAL(12,2) ) 
INSERT INTO #ResourceTimeTypeCost 
SELECT 'ResourceA' as resourcecode, 'Normal' as timetypecode, '2012-04-30' as effectivedate, 40.00 as costrate
UNION ALL
SELECT 'ResourceA', 'Normal', '2012-05-04', 50.00

IF OBJECT_ID ('tempdb..#TimeEntered') IS NOT NULL DROP TABLE #TimeEntered
CREATE TABLE #TimeEntered (  ResourceCode VARCHAR(32),  TimeTypeCode VARCHAR(32),  ProjectCode VARCHAR(32),  ActivityCode VARCHAR(32),  TimeEnteredDate DATETIME,  HoursWorked DECIMAL(12,2) ) 
INSERT INTO #TimeEntered 
SELECT 'ResourceA','Normal','Project1','Management1','2012-04-30',7.5 
UNION ALL SELECT 'ResourceA','Normal','Project1','Management1','2012-05-01',7.5 
UNION ALL SELECT 'ResourceA','Normal','Project1','Management1','2012-05-02',7.5 
UNION ALL SELECT 'ResourceA','Normal','Project1','Management1','2012-05-03',7.5 
UNION ALL SELECT 'ResourceA','Normal','Project1','Management1','2012-05-04',7.5 
UNION ALL SELECT 'ResourceA','Normal','Project1','Management1','2012-05-07',7.5 
UNION ALL SELECT 'ResourceA','Normal','Project1','Management1','2012-05-08',7.5 

;with ranges as
(
select 
resourcecode 
,TimeTypeCode
,EffectiveDate
,costrate
,row_number() OVER (PARTITION BY resourcecode,timetypecode ORDER BY effectivedate ASC) as row
from #ResourceTimeTypeCost 
)
,ranges2 AS
(
SELECT 
r1.resourcecode 
,r1.TimeTypeCode
,r1.EffectiveDate
,r1.costrate
,r1.effectivedate as start_date
,ISNULL(DATEADD(ms,-3,r2.effectivedate),GETDATE()) as end_date
FROM ranges r1
LEFT OUTER JOIN ranges r2 on r2.row = r1.row + 1 --joins onto the next date row
                    AND r2.resourcecode = r1.resourcecode 
                    AND r2.TimeTypeCode = r1.TimeTypeCode
)
SELECT 
tee.resourcecode
,tee.timetypecode
,tee.projectcode
,tee.activitycode
,SUM(ranges2.costrate * tee.hoursworked) as total_cost
FROM #TimeEntered tee
INNER JOIN ranges2 ON tee.TimeEnteredDate >= ranges2.start_date
                    AND tee.TimeEnteredDate <= ranges2.end_date
                    AND tee.resourcecode = ranges2.resourcecode
                    AND tee.timetypecode = ranges2.TimeTypeCode
GROUP BY tee.resourcecode
,tee.timetypecode
,tee.projectcode
,tee.activitycode
于 2012-05-17T10:44:00.587 に答える
2

これを試してみてください。CROSS APPLYは、TimeEntered からの現在のレコードと同じ ResourceCode および TimeTypeCode と同じかそれより古い日付を持つ最初の ResourceTimeTypeCost を見つけます。

SELECT te.ResourceCode,
       te.TimeTypeCode,
       te.ProjectCode,
       te.ActivityCode,
       te.TimeEnteredDate,
       te.HoursWorked,
       te.HoursWorked * rttc.CostRate Cost
FROM TimeEntered te 
CROSS APPLY
(
  -- First one only
  SELECT top 1 CostRate
    FROM ResourceTimeTypeCost
   WHERE te.ResourceCode = ResourceTimeTypeCost.ResourceCode
     AND te.TimeTypeCode = ResourceTimeTypeCost.TimeTypeCode
     AND te.TimeEnteredDate >= ResourceTimeTypeCost.EffectiveDate
   -- By most recent date
   ORDER BY ResourceTimeTypeCost.EffectiveDate DESC
) rttc

残念ながら、msdn で記事を見つけることができなくなったため、上記のリンクにブログがあります。

ライブ テスト @ Sql Fiddle

于 2012-05-17T10:45:13.527 に答える