2017-05-17 5 views
3

Ich versuche, Lohn je nach spätem Anwesenheitszähler des Mitarbeiters abzuziehen. Also meine Bedingung ist: wenn ein Angestellter kontinuierlich 3 Tage (außer Freitag und Samstag - Wöchentliche Feiertage) kommt, wird ein Tagesgehalt abgezogen. Die Probe ist wie folgt, und das ist, was ich habe jetzt mit der angegebenen Abfrage:Mitarbeiter Lohnabzug auf Bedingung

Name PunchDate    Attendance PerDaySal   Status  
John 2017-05-12 00:00:00.000 W  461.538461538462 Weekly 
John 2017-05-13 00:00:00.000 W  461.538461538462 Weekly 
John 2017-05-14 09:00:00.000 P  461.538461538462 On Time 
John 2017-05-15 09:16:00.000 P  461.538461538462 Late 
John 2017-05-16 09:18:00.000 P  461.538461538462 Late 
John 2017-05-17 09:20:00.000 P  0     Late -- On 3rd consecutive day 
John 2017-05-18 09:26:00.000 P  461.538461538462 Late 
John 2017-05-19 00:00:00.000 W  461.538461538462 Weekly 
John 2017-05-20 00:00:00.000 W  461.538461538462 Weekly 
John 2017-05-21 09:18:00.000 P  461.538461538462 Late 
John 2017-05-22 09:28:00.000 P  0     Late -- On the next 3rd consecutive day (Possibly 6th)   
John 2017-05-23 09:28:00.000 P  461.538461538462 Late    

Im oben, wenn es um die Teilnahme spät am dritten Tag in Folge zählen kommt, dann wird der Abzug stattfindet. Erinnern wir uns nochmals, das muss Freitag und Samstag ausgeschlossen sein. Ich bin in der Lage, die späte Zählung und die wöchentlichen Feiertage zu zeigen, aber nicht sicher, wie ich mit dem Abzug fortfahren würde. Ich plane eine Tabelle Deduktion für den Abzug Zweck zu machen, um die Tage zu speichern, wie folgt, wenn ich mich nicht täusche:

ID Days 
1  3 ---- On 3rd late count, PerDaySal 0 
2  6 ---- On 6th late count, PerDaySal 0 and so on 

Aber für bestimmte Monat (auch je 3 Tage), wie würde die Logik validiert werden ? Ich habe versucht, eine dumme ein (nie eine Lösung, obwohl gehen):

SELECT k.NAME AS Employee, m.PunchDate, 

(CASE WHEN o.WeekName = 'Friday' OR o.WeekName = 'Saturday' THEN 'W' ELSE m.Status END) 
AS Attendance, 

(CASE WHEN o.WeekName = 'Friday' OR o.WeekName = 'Saturday' THEN 0 ELSE (k.SALARY/26) END) 
AS PerDaySal, 

(CASE WHEN CONVERT(CHAR(8), m.PunchDate, 108) > '09:15:00' THEN 'Late' 
WHEN CONVERT(CHAR(8), m.PunchDate, 108) >= '09:00:00' AND CONVERT(CHAR(8), m.PunchDate, 108) <= '09:15:00' THEN 'On Time' 
WHEN o.WeekName = 'Friday' OR o.WeekName = 'Saturday' AND CONVERT(CHAR(8), m.PunchDate, 108) <= '00:00:00' THEN 'Weekly' END) AS Status 

--The silly one - (CASE WHEN COUNT(CONVERT(CHAR(8), m.PunchDate, 108) > '09:15:00') > 3 THEN 0 ELSE (k.SALARY/26) END) AS PerDaySal 

FROM @Attendances m INNER JOIN @Employee k ON k.ID = m.EmpId 
LEFT JOIN @Weekly o ON o.WeekDate = m.PunchDate 
GROUP BY k.NAME, m.PunchDate, m.Status, k.Salary, o.WeekName 

Hier sind die Tabellenstrukturen mit Beispieldaten:

declare @Attendances table (Id int not null identity(1,1) primary key,EmpId int,PunchDate datetime,Status nvarchar(4)); 
insert into @Attendances([EmpId],[PunchDate],[Status]) values 
(2,cast(0x0000A77200000000 as datetime),N'A') 
,(2,cast(0x0000A77100000000 as datetime),N'A') 
,(2,cast(0x0000A776009A5BA0 as datetime),N'P') 
,(2,cast(0x0000A775009450C0 as datetime),N'P') 
,(2,cast(0x0000A77400982920 as datetime),N'P') 
,(2,cast(0x0000A773009450C0 as datetime),N'P'); 

declare @Employee table (ID int not null primary key,NAME nvarchar(50),ADDRESS nvarchar(max),SALARY float); 
insert @Employee([ID], [NAME], [ADDRESS], [SALARY]) values 
(1, N'John', N'Germany', 12000) 
,(2, N'Jack', N'France', 14000); 

declare @Weekly table (WeekID int not null primary key,WeekNAME nvarchar(20),WeekDate datetime,Status nvarchar(10)); 
insert @Weekly([WeekID], [WeekName], [WeekDate], [Status]) values 
(1, N'Friday', CAST(0x0000A77100000000 AS DateTime), N'W') 
,(2, N'Saturday', CAST(0x0000A77200000000 AS DateTime), N'W'); 
+2

Nur eine Anmerkung, um Ihnen für das Testdatenskript zu danken! Allerdings sollen die Tabellen 'Employee' und 'Weekly' leer sein? – iamdave

+1

Warum ist 'PerDaySal' 0 auf' 2017-05-22', wenn Sie 'Late' nicht zählen, wenn es am Samstag' 2017-05-20' auftritt. – SqlZim

+0

Willkommen @iamdave. Ich versuche es so einfach wie möglich zu machen. Ich freue mich auf. ** Hinweis: ** Macht nichts. Posted den Rest der Skripte. –

Antwort

2

Ihre Beispieltabelle verwenden anstelle der mehreren Tabellen, mit einem gemeinsamen Tisch Ausdruck und Fensterfunktionen mit einem case Ausdruck, um einen Tag nicht als spät zu zählen, wenn es am Freitag oder Samstag laut der Fragespezifikation zum Zeitpunkt dieses Schreibens war.

;with cte as (
select * 
    , rn = row_number() over (partition by Name order by punchDate) 
    , DayName = datename(weekday,punchdate) 
    , LateDays = (select sum(
    case when datename(weekday,punchdate) not in ('Friday','Saturday') and [Status]='Late' 
     then 1 else 0 end 
) 
    from t i 
    where i.Name = t.Name and i.PunchDate <= t.PunchDate 
) 
from t 
) 
select 
    cte.Name 
    , cte.PunchDate 
    , cte.DayName 
    , cte.Attendance 
    , PerDaysSal = case when z.rn is not null then 0 
     else cte.PerDaySal end 
    , cte.Status 
    , cte.rn 
    , cte.LateDays 
from cte 
    left join (
    select i.Name, rn=min(i.rn) 
    from cte i 
    where i.LateDays > 0 
     and i.LateDays % 3 = 0 
    group by Name, LateDays 
    ) z 
    on cte.Name = z.Name 
and cte.rn = z.rn 

rextester Demo: http://rextester.com/ETOI35350

kehrt:

+------+---------------------+-----------+------------+---------------+---------+----+----------+ 
| Name |  PunchDate  | DayName | Attendance | PerDaysSal | Status | rn | LateDays | 
+------+---------------------+-----------+------------+---------------+---------+----+----------+ 
| John | 12.05.2017 00:00:00 | Friday | W   | 461,538461538 | Weekly | 1 |  0 | 
| John | 13.05.2017 00:00:00 | Saturday | W   | 461,538461538 | Weekly | 2 |  0 | 
| John | 14.05.2017 00:00:00 | Sunday | P   | 461,538461538 | On Time | 3 |  0 | 
| John | 15.05.2017 00:00:00 | Monday | P   | 461,538461538 | Late | 4 |  1 | 
| John | 16.05.2017 00:00:00 | Tuesday | P   | 461,538461538 | Late | 5 |  2 | 
| John | 17.05.2017 00:00:00 | Wednesday | P   | 0,000000000 | Late | 6 |  3 | 
| John | 18.05.2017 00:00:00 | Thursday | P   | 461,538461538 | Late | 7 |  4 | 
| John | 19.05.2017 00:00:00 | Friday | W   | 461,538461538 | Weekly | 8 |  4 | 
| John | 20.05.2017 00:00:00 | Saturday | P   | 461,538461538 | Late | 9 |  4 | 
| John | 21.05.2017 00:00:00 | Sunday | P   | 461,538461538 | On Time | 10 |  4 | 
| John | 22.05.2017 00:00:00 | Monday | P   | 461,000000000 | Late | 11 |  5 | 
| John | 23.05.2017 00:00:00 | Tuesday | P   | 0,000000000 | Late | 12 |  6 | 
+------+---------------------+-----------+------------+---------------+---------+----+----------+ 

Statt Partitionierung durch Name, sollte es durch EmpId partitioniert werden, wenn die tatsächlichen Tabellen. Sie können auch die id aus Anwesenheit anstelle der row_number() verwenden, die zur Nummerierung der Zeilen verwendet wird.

+0

Egal @SqlZim. Zeit ist auch ein wichtiger Faktor hier. Ich bin mir nicht sicher, ob Sie sie hier behandelt haben. ** Probe: ** Die rechtzeitige ist zwischen 9:00:00 und 9:15:00 oder spät zu zählen. Ich habs. Es ist ein funktionierender. –

+1

@ AT-2017 Was immer Sie für zu spät halten, kann in der obigen Abfrage an die Stelle von "[Status] = 'Late'" treten. – SqlZim

+1

@ AT-2017 Alle Revisionen der Frage- und Beispieltabelle machen es schwerer zu folgen, aber hier ist eine aktualisierte Demo, die 'Late' basierend auf Uhrzeit und Wochentag berechnet und Ihre aktualisierte Beispieltabelle verwendet: http:// Rextester.com/DVF49830 – SqlZim