简体   繁体   中英

SQL Date Range - Group By Case and Min Max

I have a query below:

SELECT 
CASE a.SkedName WHEN 'Restday' THEN 1 WHEN 'No Schedule' THEN 2 ELSE 3 END AS TS,
DateAdd(Year,2,TDate) TDate,
CASE a.SkedName WHEN 'Restday' THEN '00:00:00' WHEN 'No Schedule' THEN '00:00:00' ELSE SchedTI END AS SchedTimeIn,
DateAdd(Year,2,TDate) AS DateTimeIn,
DateAdd(Year,2,TDate) AS DateTimeOut,
left(emp_firstname,1) + '. '  + left(emp_middlename,1) + '. ' + emp_lastname empName,
SkedName
FROM EmpList a
    INNER JOIN tbl_employee b ON a.EmpId = b.emp_id
    ORDER BY SchedTimeIn, a.SkedName, emp_lastname, emp_firstname

It returns this result:

TS  TDate       SchedTimeIn DateTimeIn  DateTimeOut empName         SkedName

2   2017-04-01  00:00:00    2017-04-01  2017-04-01  L. C. Manalo    No Schedule
2   2017-04-02  00:00:00    2017-04-02  2017-04-02  L. C. Manalo    No Schedule
2   2017-04-03  00:00:00    2017-04-03  2017-04-03  L. C. Manalo    No Schedule
2   2017-04-04  00:00:00    2017-04-04  2017-04-04  L. C. Manalo    No Schedule
1   2017-04-04  00:00:00    2017-04-04  2017-04-04  J. S. Bio       Restday
1   2017-04-05  00:00:00    2017-04-05  2017-04-05  J. S. Bio       Restday
3   2017-04-27  09:00:00    2017-04-27  2017-04-27  R. M. Jakosalem 9:00-6:00 Semi-Flexi
3   2017-04-28  09:00:00    2017-04-28  2017-04-28  R. M. Jakosalem 9:00-6:00 Semi-Flexi
3   2017-04-29  09:00:00    2017-04-29  2017-04-29  R. M. Jakosalem 9:00-6:00 Semi-Flexi

However, my desired result is to remove the redundancy of "No Schedule" and "Restday" Schedule Type.

Instead of this:

TS  TDate       SchedTimeIn DateTimeIn  DateTimeOut empName         SkedName

2   2017-04-01  00:00:00    2017-04-01  2017-04-01  L. C. Manalo    No Schedule
2   2017-04-02  00:00:00    2017-04-02  2017-04-02  L. C. Manalo    No Schedule
2   2017-04-03  00:00:00    2017-04-03  2017-04-03  L. C. Manalo    No Schedule
2   2017-04-04  00:00:00    2017-04-04  2017-04-04  L. C. Manalo    No Schedule
1   2017-04-04  00:00:00    2017-04-04  2017-04-04  J. S. Bio       Restday
1   2017-04-05  00:00:00    2017-04-05  2017-04-05  J. S. Bio       Restday

My desired result is setting TDate to MAX date of SkedName, DateTimeIn as MinDate, DateTimeOut as MaxDate of "No Schedule" and "Restday" per employee to avoid too many rows:

TS  TDate       SchedTimeIn DateTimeIn  DateTimeOut empName         SkedName

2   2017-04-04  00:00:00    2017-04-01  2017-04-04  L. C. Manalo    No Schedule
1   2017-04-05  00:00:00    2017-04-04  2017-04-05  J. S. Bio       Restday

I tried "GROUP BY SkedName HAVING SkedName = 'No Schedule' AND SkedName = 'Restday'". But it gives me an error

Column 'EmpList.TDate' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

I don't know what to do. I appreciate any answers and suggestions. Badly need help :( Thanks a lot.

You can achieve it by using cte and dense_rank() as below

;With cte as
(    
    SELECT 
    CASE a.SkedName WHEN 'Restday' THEN 1 WHEN 'No Schedule' THEN 2 ELSE 3 END AS TS,
    DateAdd(Year,2,TDate) TDate,
    CASE a.SkedName WHEN 'Restday' THEN '00:00:00' WHEN 'No Schedule' THEN '00:00:00' ELSE SchedTI END AS SchedTimeIn,
    DateAdd(Year,2,TDate) AS DateTimeIn,
    DateAdd(Year,2,TDate) AS DateTimeOut,
    left(emp_firstname,1) + '. '  + left(emp_middlename,1) + '. ' + emp_lastname empName,
    SkedName,
    dense_rank() over (partition by a.EmpId,SkedName order by DateAdd(Year,2,TDate)) as rn,
    a.EmpId as empid
    FROM EmpList a
    INNER JOIN tbl_employee b ON a.EmpId = b.emp_id
)
 Select TS,TDate,SchedTimeIn,DateTimeIn,
 case when skedname in ('No Schedule','Restday')
 then
  (Select top 1 DateTimeOut from cte where rn = (select max(rn) from cte cin where cin.empid=cout.empid and cin.skedName = cout.skedName) and empid=cout.empid and skedName=cout.skedName) 
 else
  DateTimeOut end as DateTimeOut,
 empName,SkedName
 from cte cout where rn=1 or skedName not in ('No Schedule','Restday')
 ORDER BY SchedTimeIn, SkedName, emp_lastname, emp_firstname 

尝试:

select Min(DateTimeIn),Max(DateTimeOut),empname,SkedName from Emplist group by empname,SkedName

Based on my understanding,

I have edited my answer now.

    ;WITH cte 
     AS (SELECT ts, 
                tdate, 
                schedtimein, 
                datetimein, 
                datetimeout, 
                empname, 
                skedname, 
                Row_number() 
                  OVER( 
                    partition BY skedname 
                    ORDER BY datetimein)       AS Rn_in, 
                Row_number() 
                  OVER( 
                    partition BY skedname 
                    ORDER BY datetimeout DESC) AS Rn_out 
         FROM   (SELECT CASE a.skedname 
                          WHEN 'Restday' THEN 1 
                          WHEN 'No Schedule' THEN 2 
                          ELSE 3 
                        END                                             AS TS, 
                        Dateadd(year, 2, tdate)                         TDate, 
                        CASE a.skedname 
                          WHEN 'Restday' THEN '00:00:00' 
                          WHEN 'No Schedule' THEN '00:00:00' 
                          ELSE schedti 
                        END                                             AS SchedTimeIn, 
                        Dateadd(year, 2, tdate)                         AS DateTimeIn, 
                        Dateadd(year, 2, tdate)                         AS DateTimeOut, 
                        LEFT(emp_firstname, 1) + '. ' 
                        + LEFT(emp_middlename, 1) + '. ' + emp_lastname empName, 
                        skedname 
                 FROM   emplist a 
                        INNER JOIN tbl_employee b 
                                ON a.empid = b.emp_id)A), 
     cte1 
     AS (SELECT a.ts, 
                b.tdate, 
                a.schedtimein, 
                a.datetimein, 
                b.datetimeout, 
                a.empname, 
                a.skedname, 
                a.rn_in, 
                b.rn_out 
         FROM   cte a 
                JOIN cte b 
                  ON a.ts = b.ts 
                     AND a.rn_in = b.rn_out 
         WHERE  a.skedname IN ( 'No Schedule', 'Restday' )) SELECT ts, 
       tdate, 
       schedtimein, 
       datetimein, 
       datetimeout, 
       empname, 
       skedname 
FROM   cte1 
WHERE  rn_in = 1 
UNION 
SELECT ts, 
       tdate, 
       schedtimein, 
       datetimein, 
       datetimeout, 
       empname, 
       skedname 
FROM   cte 
WHERE  skedname NOT IN ( 'No Schedule', 'Restday' ) 

Note: I have used Row_number function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM