基于日期的条件金额(合同加班费)

时间:2014-03-11 18:37:54

标签: sql sql-server tsql

我的表格包含ID(workers_id),Nametime_workedtime_to_workContract_Start_DateDate_of_Entry。此表包含工人每天的条目。我想计算他到目前为止收集的加班费。对于每个合同中的每个合同,我每个合同都有相同的条目,其中条目之间的唯一区别是Contract_STart_Datetime_to_work。一旦他得到一份新合同,他就会在那张桌子上每天得到一个新的entrie(我必须纠正那一天,但没有时间,所以认为这个问题不灵活)。

我有下表

| ID | Name  | time_worked | time_to_work | Contract_Start_Date | Date_of_Entry | 
| -- | ----  | ----------- | ------------ | ------------------- | ------------- |
| 11 | Jack  | 8           | 8            | 2013-01-01          | 2013-01-01    |
| 11 | Jack  | 8           | 8            | 2013-04-01          | 2013-01-01    |
| 11 | Jack  | 8           | 8            | 2013-01-01          | 2013-01-02    |
| 11 | Jack  | 8           | 8            | 2013-04-01          | 2013-01-02    | 
...   
| 11 | Jack  | 6           | 8            | 2013-01-01          | 2013-04-15    |
| 11 | Jack  | 6           | 4            | 2013-04-15          | 2013-04-15    |
| 11 | Jack  | 8           | 8            | 2013-01-01          | 2013-04-16    |
| 11 | Jack  | 8           | 4            | 2013-04-15          | 2013-04-16    |

我想把杰克的加班加起来作为相关合同。

我想我找到了解决这个问题的方法(逻辑上),但无法将我的想法转化为代码。这是方法:

我按合约每天设定一个数字(SeqNumber) (已经通过我的代码完成了。)

| ID | Name  | time_worked | time_to_work | Contract_Start_Date | Date_of_Entry | SeqNumber
| -- | ----  | ----------- | ------------ | ------------------- | ------------- |----------
| 11 | Jack  | 8           | 8            | 2013-01-01          | 2013-01-01    |1
| 11 | Jack  | 8           | 8            | 2013-04-01          | 2013-01-01    |2
| 11 | Jack  | 8           | 8            | 2013-01-01          | 2013-01-02    |1
| 11 | Jack  | 8           | 8            | 2013-04-01          | 2013-01-02    |2
...   
| 11 | Jack  | 6           | 8            | 2013-01-01          | 2013-04-15    |1
| 11 | Jack  | 6           | 4            | 2013-04-15          | 2013-04-15    |2
| 11 | Jack  | 8           | 8            | 2013-01-01          | 2013-04-16    |1
| 11 | Jack  | 8           | 4            | 2013-04-15          | 2013-04-16    |2

现在设置一个数字(ConSeqNumber),date_of_entry属于contract_start_date

| ID | Name  | time_worked | time_to_work | Contract_Start_Date | Date_of_Entry | SeqNumber| ConSeqNumber
| -- | ----  | ----------- | ------------ | ------------------- | ------------- |----------| ------------
| 11 | Jack  | 8           | 8            | 2013-01-01          | 2013-01-01    |1         |1
| 11 | Jack  | 8           | 8            | 2013-04-01          | 2013-01-01    |2         |1
| 11 | Jack  | 8           | 8            | 2013-01-01          | 2013-01-02    |1         |1
| 11 | Jack  | 8           | 8            | 2013-04-01          | 2013-01-02    |2         |1
...   
| 11 | Jack  | 6           | 8            | 2013-01-01          | 2013-04-15    |1         |2
| 11 | Jack  | 6           | 4            | 2013-04-15          | 2013-04-15    |2         |2
| 11 | Jack  | 8           | 8            | 2013-01-01          | 2013-04-16    |1         |2
| 11 | Jack  | 8           | 4            | 2013-04-15          | 2013-04-16    |2         |2

解决方案是对SeqNumber和ConSeqNumber相等的每个条目求和。

我的输出将是(根据计算time_worked - time_to_work并汇总值。 (8-8)+(8-8)+(6-4)+(8-4)= 6

| Overtime |
| -------- | 
| 6        | 

我的完整代码是:

select ID, Name,(sum(time_worked)-sum(time_to_work)) as 'overtime'
 from (
 Select *,
ROW_NUMBER() over (partition by Date_of_Entry order by Contract_Start_Date asc) as seqnum
from MyTable  where Contract_Start_Date <= Date_of_Entry
 )
 MyTable
 WHERE seqnum = 1
 AND YearA = DATEPART(YEAR, GETDATE()) -1
 AND DATE_of_Entry <= GETDATE()
 AND DATEPART(MONTH, Date_of_Entry) BETWEEN 4 and 9
 GROUP BY ID, Name

4 个答案:

答案 0 :(得分:0)

我还不太清楚你想要什么,所以我在下面为你提供了一些不同的选择。如果您发布所需的结果集,我们可以确保我们的解决方案符合您的要求。

DECLARE @Hours TABLE
(
    WorkerID int,
    WorkerName varchar(50),
    TimeWorked int,
    TimeToWork int,
    ContractStartDate datetime,
    DateOfEntry datetime
)

INSERT INTO @Hours (WorkerID, WorkerName, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 'Jack', 8, 8, '2013-01-01', '2013-01-01');
INSERT INTO @Hours (WorkerID, WorkerName, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 'Jack', 8, 8, '2013-01-01', '2013-01-02');
INSERT INTO @Hours (WorkerID, WorkerName, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (12, 'Norman', 7, 6, '2013-01-01', '2013-01-01');
INSERT INTO @Hours (WorkerID, WorkerName, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 'Jack', 6, 4, '2013-04-15', '2013-04-15');
INSERT INTO @Hours (WorkerID, WorkerName, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 'Jack', 7, 8, '2013-01-01', '2013-04-15');
INSERT INTO @Hours (WorkerID, WorkerName, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 'Jack', 8, 4, '2013-04-15', '2013-04-16');
INSERT INTO @Hours (WorkerID, WorkerName, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 'Jack', 4, 8, '2013-01-01', '2013-04-16');

-- If you want the total for the worker for the full contract period repeated for each line, you could use this PARTITION BY version:

SELECT
    *,
    SUM(TimeWorked-TimeToWork) OVER (PARTITION BY WorkerID, ContractStartDate) AS OverTimeForContract,
    -- if you don't want "undertime" to count against overtime, such that working 1 hour less one day doesn't absolve you from having worked 1 hour extra the previous day, you can do this fancy footwork:
    SUM(CASE WHEN TimeWorked > TimeToWork THEN TimeWorked-TimeToWork ELSE 0 END) OVER (PARTITION BY WorkerID, ContractStartDate) AS OverTimeOnlyForContract
FROM        @Hours
WHERE       DateOfEntry BETWEEN '2013-01-01' AND '2013-04-15'; -- choose whatever dates you want, of course

-- If you don't need the value repeated for each entry, you could of course do a simple GROUP BY

SELECT
    WorkerID,
    WorkerName,
    ContractStartDate,
    SUM(TimeWorked-TimeToWork) AS OverTimeForContract,
    SUM(CASE WHEN TimeWorked > TimeToWork THEN TimeWorked-TimeToWork ELSE 0 END) AS OverTimeOnlyForContract
FROM        @Hours
WHERE       DateOfEntry BETWEEN '2013-01-01' AND '2013-04-15'
GROUP BY    WorkerID,
            WorkerName,
            ContractStartDate;

答案 1 :(得分:0)

我采用了@ Riley的相同数据样本。如果我拿走你的样本数据,那么加班也是正确的,即6。

;with CTE as
(
select *,ROW_NUMBER() over (partition by workerid,DateofEntry order by ContractStartDate asc) as seqnum,
ROW_NUMBER() over (partition by workerid order by workerid asc) as seqnum1
 from @Hours 
)
,CTE1 as
(
select WorkerID,sum(timeworked - timetowork)overtime from cte where seqnum=1 group by WorkerID
)
select a.WorkerID,a.WorkerName,b.overtime from cte a inner join cte1 b on a.WorkerID=b.WorkerID
where a.seqnum1=1

答案 2 :(得分:0)

以下方法获取最新合同的条目(通过检查没有其他条目具有较新的合同开始日期),然后查找time_worked和time_to_work之间的差异。

select
    ID, Name, SUM(time_worked - time_to_work) as overtime, MAX(Contract_Start_Date) AS Contract_Start_Date
from
    TimeEntry T1
WHERE
    NOT EXISTS
(
SELECT 1 
FROM
    TimeEntry T2
WHERE   T2.ID = T1.ID
AND T2.Date_of_Entry = T1.Date_of_Entry
AND T2.Contract_Start_Date > T1.Contract_Start_Date
)
GROUP BY ID, Name;

我很快就会创建一个SQL小提琴。

答案 3 :(得分:0)

好的,看起来我找到了解决方案:

数据样本

CREATE TABLE #test(WorkerID int,
    TimeWorked int,
    TimeToWork int,
    ContractStartDate datetime,
    DateOfEntry datetime
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 8, 8, '2013-01-01', '2013-01-01');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 8, 4, '2013-04-15', '2013-01-01');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 8, 6, '2013-08-15', '2013-01-01');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 8, 8, '2013-01-01', '2013-01-02');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 8, 4, '2013-04-15', '2013-01-02');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 8, 6, '2013-08-15', '2013-01-02');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 7, 8, '2013-01-01', '2013-04-15');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 6, 4, '2013-04-15', '2013-04-15');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 6, 6, '2013-08-15', '2013-04-15');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 4, 8, '2013-01-01', '2013-04-16');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 8, 4, '2013-04-15', '2013-04-16');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 4, 6, '2013-08-15', '2013-04-16');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 2, 8, '2013-01-01', '2013-08-16');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 2, 6, '2013-04-15', '2013-08-16');
INSERT INTO #test (WorkerID, TimeWorked, TimeToWork, ContractStartDate, DateOfEntry) VALUES (11, 2, 5, '2013-08-15', '2013-08-16');

并且我得到了我想要的东西。非常感谢大家的帮助!

---select WorkerID,(sum(TimeWorked)-sum(TimeToWork)) as 'overtime'
select * ---sum(timeworked - timetowork) 
 from (
 Select *,
ROW_NUMBER() over (partition by DateOfEntry order by ContractStartDate desc) as seqnum
from #test 
where ContractStartDate <= DateOfEntry)
#test
where seqnum = 1

drop table #test