将劳工成本与工时表匹配 – 每人每天的费率

huangapple go评论61阅读模式
英文:

Matching labour costs to a timesheet - rate per person per day

问题

Sure, here's the translated content:

"我在尝试找到每个员工在特定日期使用的正确费率时遇到了困难。

对于每个日期、员工ID和费率类型,找到正确的费率金额。然后,我需要高效地将这两者相乘。所示数据的格式与我在工作中要处理的数据类似。

工作时间表格式

日期	        员工ID	费率    工作小时数	费率金额	劳动成本
3/01/2020	JBR001	BR1	8		
10/01/2020	JBR001	BR1	8		
10/01/2020	JBR001	OT1	4		
17/01/2020	JBR001	BR1	8		
24/01/2020	JBR001	BR1	8		
31/01/2020	JBR001	BR1	8		
7/02/2020	JBR001	BR1	8		
14/02/2020	JBR001	BR1	8		
13/03/2020	JBR001	BR1	8		
20/03/2020	JBR001	BR1	8		
20/03/2020	JBR001	OT1	4		
27/03/2020	JBR001	BR1	8		
3/04/2020	JBR001	BR1	8		
17/04/2020	JBR001	BR1	8		
4/01/2020	BJL001	BR1	8		
10/01/2020	BJL001	BR1	8		
27/02/2020	BJL001	BR1	8		
27/02/2020	BJL001	OT1	3		
4/03/2020	BJL001	BR1	8		
10/03/2020	BJL001	BR1	8		
10/03/2020	BJL001	OT1	4		
28/03/2020	BJL001	BR1	8		
3/04/2020	BJL001	BR1	8		

劳动费率表

员工ID	费率	费率开始日期	费率金额
JBR001	BR1	1/01/2020	10
JBR001	BR1	1/03/2020	11
JBR001	OT1	1/01/2020	15
JBR001	OT1	1/04/2020	16
BJL001	BR1	1/01/2020	12
BJL001	BR1	1/03/2020	13
BJL001	OT1	1/01/2020	15
BJL001	OT1	1/04/2020	16

如果有人能告诉我如何将这些信息合并在一起,我将非常感激。
谢谢!

我已经成功地在PowerQuery/M中组合了这些信息,但查询非常慢。我希望有人能与我分享T-SQL的威力!"

英文:

I'm having difficulty trying to find the correct rate to use for each employee on a given date.

For each Date, Employee ID and Rate Type, Find the correct Rate Amount. I then need to multiply those two efficiently. The data shown is similar in format to what I'm trying to process in my role.

Timesheet Format

Date	        EmpID	Rate    HoursWorked	RateAmount	LabourCost
3/01/2020	JBR001	BR1	8		
10/01/2020	JBR001	BR1	8		
10/01/2020	JBR001	OT1	4		
17/01/2020	JBR001	BR1	8		
24/01/2020	JBR001	BR1	8		
31/01/2020	JBR001	BR1	8		
7/02/2020	JBR001	BR1	8		
14/02/2020	JBR001	BR1	8		
13/03/2020	JBR001	BR1	8		
20/03/2020	JBR001	BR1	8		
20/03/2020	JBR001	OT1	4		
27/03/2020	JBR001	BR1	8		
3/04/2020	JBR001	BR1	8		
17/04/2020	JBR001	BR1	8		
4/01/2020	BJL001	BR1	8		
10/01/2020	BJL001	BR1	8		
27/02/2020	BJL001	BR1	8		
27/02/2020	BJL001	OT1	3		
4/03/2020	BJL001	BR1	8		
10/03/2020	BJL001	BR1	8		
10/03/2020	BJL001	OT1	4		
28/03/2020	BJL001	BR1	8		
3/04/2020	BJL001	BR1	8		

Labour Rate Table

EmpID	Rate	RateStart	RateAmount
JBR001	BR1	1/01/2020	10
JBR001	BR1	1/03/2020	11
JBR001	OT1	1/01/2020	15
JBR001	OT1	1/04/2020	16
BJL001	BR1	1/01/2020	12
BJL001	BR1	1/03/2020	13
BJL001	OT1	1/01/2020	15
BJL001	OT1	1/04/2020	16

If somebody could advise me how to go about mashing this information together I would be very grateful.
Thank you!

I have been successful in combining this information in PowerQuery/M, but the query was very very slow. I'm hoping somebody could share the power of T-SQL with me!

答案1

得分: 1

以下是翻译好的代码部分:

获取 Timesheet 条目的有效 RateAmount 的一种方法是使用相关的 TOP 1 查询([示例][1]

SELECT TS.*,
       LR.RateAmount
FROM   Timesheet TS
       CROSS APPLY (SELECT TOP 1 *
                    FROM   LabourRate LR
                    WHERE  TS.EmpId = LR.EmpId
                           AND TS.Rate = LR.Rate
                           AND LR.RateStart <= TS.Date
                    ORDER  BY LR.RateStart DESC) LR 

上述查询需要在 LabourRate 表上建立索引

LabourRate(EmpId,Rate,RateStart) INCLUDE ( RateAmount) 

如果表不太大,上述方法可能足够 - 不过还有其他潜在更有效的方法。

如果你使用的是 SQL Server 2022,可以考虑使用 `LAST_VALUE`  `IGNORE NULLS` 选项来跟踪有效汇率,而不需要相关的查询([示例 2][2]

WITH T1 AS
(
SELECT 1 AS Code, [Date], EmpId, Rate, HoursWorked, NULL AS RateAmount
FROM   Timesheet
UNION ALL
SELECT 0 AS Code, [RateStart],[EmpId], [Rate], NULL, RateAmount
FROM LabourRate
), T2 AS
(
SELECT *, 
       EffectiveRateAmount = LAST_VALUE(RateAmount) IGNORE NULLS OVER (PARTITION BY EmpId, Rate ORDER BY [Date], Code)
FROM T1
)
SELECT [Date], EmpId, Rate, HoursWorked, EffectiveRateAmount
FROM T2
WHERE Code = 1
英文:

One way of getting the effective RateAmount for a Timesheet entry is a correlated TOP 1 query (Fiddle)

SELECT TS.*,
       LR.RateAmount
FROM   Timesheet TS
       CROSS APPLY (SELECT TOP 1 *
                    FROM   LabourRate LR
                    WHERE  TS.EmpId = LR.EmpId
                           AND TS.Rate = LR.Rate
                           AND LR.RateStart <= TS.Date
                    ORDER  BY LR.RateStart DESC) LR 

The above will need an index on

LabourRate(EmpId,Rate,RateStart) INCLUDE ( RateAmount) 

If the tables aren't too large the above will likely be adequate - though there are other potentially more efficient ways.

If you are on SQL Server 2022 the IGNORE NULLS option to LAST_VALUE could also potentially be useful here to keep track of the effective rate without needing a correlated query (Fiddle 2)

WITH T1 AS
(
SELECT 1 AS Code, [Date], EmpId, Rate, HoursWorked, NULL AS RateAmount
FROM   Timesheet
UNION ALL
SELECT 0 AS Code, [RateStart],[EmpId], [Rate], NULL, RateAmount
FROM LabourRate
), T2 AS
(
SELECT *, 
       EffectiveRateAmount = LAST_VALUE(RateAmount) IGNORE NULLS OVER (PARTITION BY EmpId, Rate ORDER BY [Date], Code)
FROM T1
)
SELECT [Date], EmpId, Rate, HoursWorked, EffectiveRateAmount
FROM T2
WHERE Code = 1

答案2

得分: 1

你可以使用CROSS APPLY(SELECT TOP 1 ...)模式来为每个工作记录选择适当的费率金额。CROSS APPLY类似于与子查询的连接,该子查询可以引用FROM子句中较早的表。

在你的情况下,看起来你需要匹配EmpIDRate,然后选择劳动费率表中RateStart值等于或小于工作时间的最新行。

可以按如下方式完成:

SELECT T.*, R.RateAmount, T.HoursWorked * R.RateAmount AS LabourCost
FROM TimeSheet T
OUTER APPLY (
    -- 截至工作时间的最近费率
    SELECT TOP 1 *
    FROM LabourRateTable R
    WHERE R.EmpID = T.EmpID
    AND R.Rate = T.Rate
    AND R.RateStart <= T.Date
    ORDER BY R.RateStart DESC
) R
ORDER BY T.EmpID, T.Date

请注意,我使用了OUTER APPLY而不是CROSS APPLYOUTER APPLY类似于CROSS APPLY的左连接变体。如果找不到匹配项,它将返回一个结果,其RateAmount值为null(并且计算的LabourCost也为null)。如果你的数据良好,这不应发生,但与悄悄地丢弃不匹配的数据相比,可能更倾向于返回null值。

在这个 db<>fiddle 中有一个演示。

示例结果:

日期 EmpID 费率 工作小时数 费率金额 劳动成本
2020-01-04 BJL001 BR1 8 12 96
2020-01-10 BJL001 BR1 8 12 96
2020-02-27 BJL001 BR1 8 12 96
2020-02-27 BJL001 OT1 3 15 45
2020-03-04 BJL001 BR1 8 13 104
2020-03-10 BJL001 BR1 8 13 104
2020-03-10 BJL001 OT1 4 15 60
2020-03-28 BJL001 BR1 8 13 104
2020-04-03 BJL001 BR1 8 13 104
2020-01-03 JBR001 BR1 8 10 80
2020-01-10 JBR001 BR1 8 10 80
2020-01-10 JBR001 OT1 4 15 60
2020-01-17 JBR001 BR1 8 10 80
2020-01-24 JBR001 BR1 8 10 80
2020-01-31 JBR001 BR1 8 10 80
2020-02-07 JBR001 BR1 8 10 80
2020-02-14 JBR001 BR1 8 10 80
2020-03-13 JBR001 BR1 8 11 88
2020-03-20 JBR001 BR1 8 11 88
2020-03-20 JBR001 OT1 4 15 60
2020-03-27 JBR001 BR1 8 11 88
2020-04-03 JBR001 BR1 8 11 88
2020-04-17 JBR001 BR1 8 11 88
英文:

You can use a CROSS APPLY(SELECT TOP 1 ...) pattern to select the appropriate rate amount for each timesheet record. A CROSS APPLY is like a join to a subquery, where that subquery can reference tables earlier in the FROM clause.

In your case, it appears that you need to match on EmpID and Rate, and then select the latest Labour Rate Table row with a RateStart value equal or less than the timesheet date.

This can be done as follows:

SELECT T.*, R.RateAmount, T.HoursWorked * R.RateAmount AS LabourCost
FROM TimeSheet T
OUTER APPLY (
    -- Most recent rate as of timesheet date
    SELECT TOP 1 *
    FROM LabourRateTable R
    WHERE R.EmpID = T.EmpID
    AND R.Rate = T.Rate
    AND R.RateStart &lt;= T.Date
    ORDER BY R.RateStart DESC
) R
ORDER BY T.EmpID, T.Date

Note that I used an OUTER APPLY instead of a CROSS APPLY. An outer apply is like a left join variant of a cross apply. If no match is found, it will still return a result having null RateAmount value (and null calculated LabourCost). This should not occur if your data is good, but returning null values may be preferred over quietly discarding unmatched data.

See this db<>fiddle for a demo.

Sample results:

Date EmpID Rate HoursWorked RateAmount LabourCost
2020-01-04 BJL001 BR1 8 12 96
2020-01-10 BJL001 BR1 8 12 96
2020-02-27 BJL001 BR1 8 12 96
2020-02-27 BJL001 OT1 3 15 45
2020-03-04 BJL001 BR1 8 13 104
2020-03-10 BJL001 BR1 8 13 104
2020-03-10 BJL001 OT1 4 15 60
2020-03-28 BJL001 BR1 8 13 104
2020-04-03 BJL001 BR1 8 13 104
2020-01-03 JBR001 BR1 8 10 80
2020-01-10 JBR001 BR1 8 10 80
2020-01-10 JBR001 OT1 4 15 60
2020-01-17 JBR001 BR1 8 10 80
2020-01-24 JBR001 BR1 8 10 80
2020-01-31 JBR001 BR1 8 10 80
2020-02-07 JBR001 BR1 8 10 80
2020-02-14 JBR001 BR1 8 10 80
2020-03-13 JBR001 BR1 8 11 88
2020-03-20 JBR001 BR1 8 11 88
2020-03-20 JBR001 OT1 4 15 60
2020-03-27 JBR001 BR1 8 11 88
2020-04-03 JBR001 BR1 8 11 88
2020-04-17 JBR001 BR1 8 11 88

huangapple
  • 本文由 发表于 2023年6月29日 11:00:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76577813.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定