Find min and max data from multiple columns - sql-server

I have a table that specifies exactly what date and time each employee was in a particular office.I want to know on what date and time each employee arrived at work and on what date and time he left work. I also want to know how many times he has been at work in each time process.
EmployeeTable looks like this:
id
EmployeeID
DateP
TimeP
1
11111
1397/01/02
01:30
2
11111
1398/05/09
05:30
3
11111
1398/06/07
05:10
4
22222
1398/08/09
06:12
5
22222
1399/02/01
07:15
6
11111
1399/07/02
08:51
7
11111
1399/08/06
12:20
8
33333
1399/09/04
20:01
9
33333
1399/12/08
22:05
10
33333
1400/01/01
23:11
11
33333
1400/02/05
14:10
12
22222
1400/04/05
16:25
I want exactly select Min and Max date and time for each Employee when present in a office and how many times he/she has been present at work in each stage.:
id
EmployeeID
MinDateP
TimeMinDateP
MaxDateP
TimeMaxDateP
Count
1
11111
1397/01/02
01:30
1398/06/07
05:10
3
2
22222
1398/08/09
06:12
1399/02/01
07:15
2
3
11111
1399/07/02
08:51
1399/08/06
12:20
2
4
33333
1399/09/04
20:01
1400/02/05
14:10
4
5
22222
1400/04/05
16:25
1400/04/05
16:25
1
This is the SQL code that indicates exactly when each employee arrived at work and when he or she left work :
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (ORDER BY DateP, TimeP) rn1,
ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY DateP, TimeP) rn2
FROM
EmployeeTable
),
cte2 AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY EmployeeID, rn1 - rn2
ORDER BY DateP, TimeP) rn_first,
ROW_NUMBER() OVER (PARTITION BY EmployeeID, rn1 - rn2
ORDER BY DateP DESC, TimeP DESC) rn_last
FROM
cte
)
SELECT
EmployeeID,
MAX(CASE WHEN rn_first = 1 THEN DateP END) AS MinDateP,
MAX(CASE WHEN rn_first = 1 THEN TimeP END) AS TimeMinDateP,
MAX(CASE WHEN rn_last = 1 THEN DateP END) AS MaxDateP,
MAX(CASE WHEN rn_last = 1 THEN TimeP END ) AS TimeMaxDateP
FROM
cte2
GROUP BY
EmployeeID,
rn1 - rn2
ORDER BY
MIN(DateP), MIN(TimeP);
But I want to know how many times each employee has been at work at any given time (Count column)
Can anybody help me?

If I understand correctly, you just want to know the number of records in each employee island. In that case, just select COUNT(*) in your final query:
SELECT
EmployeeID,
MAX(CASE WHEN rn_first = 1 THEN DateP END) AS MinDateP,
MAX(CASE WHEN rn_first = 1 THEN TimeP END) AS TimeMinDateP,
MAX(CASE WHEN rn_last = 1 THEN DateP END) AS MaxDateP,
MAX(CASE WHEN rn_last = 1 THEN TimeP END) AS TimeMaxDateP,
COUNT(*) AS count
FROM cte2
GROUP BY
EmployeeID,
rn1 - rn2
ORDER BY
MIN(DateP),
MIN(TimeP);

Related

Retrieve multiple rows into single row based on FK SQL Server 2014

I have the following table:
ID_TableDetails
FK_TableMaster
StartDate
EndDate
StartTime
EndTime
1
1
2021-05-24
2021-05-24
10:00
11:00
2
1
2021-05-25
2021-05-25
10:00
11:00
3
1
2021-05-26
2021-05-26
11:00
12:00
4
2
2021-05-27
2021-05-27
11:00
12:00
5
2
2021-05-28
2021-05-28
11:00
12:00
6
2
2021-05-29
2021-05-29
11:00
12:00
I want to select values from the above table in the following manner
1stID
2ndID
3rdID
1stStartDte
1stStartTimeEndTime
2ndStartDte
2ndStartTimeEndTime
3rdStartDte
3rdStartTimeEndTime
1
2
3
2021-05-24
10:00 TO 11:00
2021-05-25
10:00 TO 11:00
2021-05-26
11:00 TO 12:00
4
5
6
2021-05-24
10:00 TO 11:00
2021-05-25
10:00 TO 11:00
2021-05-26
11:00 TO 12:00
There will always be three entries for FK_TableMaster and I want to select is as one row.
This is what I have tried
SELECT
ID_TableDetils, Description, Startate, EndDate, StartTime, EndTime
FROM
TableDetils AS TD
JOIN
TableMaster AS TM ON TD.ID_TableDetils = TM.FK_TableMaster
This will return multiple rows for FK_TableMaster - I don't know how to select it as a single row any help would be appreciated.
UPDATE based on :Group by column and multiple Rows into One Row multiple columns
WITH RNs AS
(
SELECT ID_TableDetails,
FK_TableMaster,
StartDate,
EndDate,
ROW_NUMBER() OVER (PARTITION BY ID_PtaEventScheduleDetails, FK_PtaEventSchedule ORDER BY (SELECT NULL)) AS RN --ORDER BY should be your ID/always ascending column
FROM dbo.TableDetails
WHERE Cancelled = 0 AND FK_TableMaster = 1
)
SELECT
ID_TableDetails,
FK_TableMaster,
MAX(CASE RN WHEN 1 THEN StartDate END) AS Result1,
MAX(CASE RN WHEN 2 THEN StartDate END) AS Result2,
MAX(CASE RN WHEN 3 THEN StartDate END) AS Result3,
MAX(CASE RN WHEN 1 THEN EndDate END) AS Result4,
MAX(CASE RN WHEN 1 THEN EndDate END) AS Result5,
MAX(CASE RN WHEN 1 THEN EndDate END) AS Result6
FROM
RNs R
GROUP BY
ID_TableDetails, FK_TableMaster
This is a duplicate of the proposed dupe candidate Group by column and multiple Rows into One Row multiple columns but to post the same answer again, replacing the columns from my other answer with the OP's:
WITH RNs AS(
SELECT ID_TableDetails,
FK_TableMaster,
StartDate,
EndDate,
StartTime,
EndTime,
ROW_NUMBER() OVER (PARTITION BY FK_TableMaster ORDER BY ID_TableDetails) AS RN
FROM dbo.Result)
SELECT MAX(CASE RN WHEN 1 THEN ID_TableDetails END) AS ID1,
MAX(CASE RN WHEN 2 THEN ID_TableDetails END) AS ID2,
MAX(CASE RN WHEN 3 THEN ID_TableDetails END) AS ID3,
MAX(CASE RN WHEN 1 THEN StartDate END) AS StartDate1,
MAX(CASE RN WHEN 1 THEN StartTime END) AS StartTime1,
MAX(CASE RN WHEN 1 THEN EndTime END) AS EndTime1,
... --You get the idea
MAX(CASE RN WHEN 3 THEN EndTime END) AS EndTime3
FROM RNs R
GROUP BY FK_TableMaster;

How to transpose min/max value to columns in SQL Server using Partition?

I want to get the MIN and MAX from a certain values and put them in columns beside each other. Here's my query but I don't know how to transpose the values...
SELECT *
, MIN([CID]) OVER (PARTITION BY [TID] ORDER BY [TID]) MinID
, MAX([CID]) OVER (PARTITION BY [TID] ORDER BY [TID]) MaxID
Given:
TID CID DATE
123456789 1 01JAN
123456789 2 02JAN
123456789 3 03JAN
123456789 4 04JAN
Result:
TID CID DATE MIN MAX DATEMIN DATEMAX
123456789 1 01JAN 1 4 01JAN 04JAN
Isn't simple aggregation good enough here?
select
tid,
min(cid) min_cid,
max(cid) max_cid,
min(date) min_date,
max(date) max_date
from mytable
group by tid
Or, if the cids and dates are not changing accordingly, you can use conditional aggregation:
select
tid,
max(case when rn_asc = 1 then cid end) cid_at_min_date,
max(case when rn_desc = 1 then cid end) cid_at_max_date,
min(date) min_date,
max(date) max_date
from (
select
t.*,
row_number() over(partition by tid order by cdate asc ) rn_asc,
row_number() over(partition by tid order by cdate desc) rn_desc
from mytable t
) t
where 1 in (rn_asc, rn_desc)
group by tid
This orders records by cdate, and gives you the cids that correspond to the minimum and maximum date. You can easily adapt the query if you want things the other way around (basically, switch cid and cdate).

Combine text from multiple rows into one row

I have set of rows that shows transfer locations for employees as below. The end location for the previous row will be the start location for the next. There are over 50,000 employees.
Employee name transfer_date start_location end_location
AA 1/1/2017 Canada US
AA 1/1/2018 US Italy
AA 1/1/2019 Italy Australia
BB 2/1/2016 Spain US
BB 2/1/2019 US Luxembourg
I need to convert this as:
Employee name start_location next_location1 next_location2 next_location3
AA Canada US Italy Australia
BB Spain US Luxembourg NULL
Pivoting with the help of ROW_NUMBER is one option here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY [Employee name] ORDER BY transfer_date) rn
FROM yourTable
)
SELECT
[Employee name],
MAX(CASE WHEN rn = 1 THEN start_location END) AS start_location,
MAX(CASE WHEN rn = 1 THEN end_location END) AS next_location1,
MAX(CASE WHEN rn = 2 THEN end_location END) AS next_location2,
MAX(CASE WHEN rn = 3 THEN end_location END) AS next_location3
FROM cte
GROUP BY
[Employee name]
ORDER BY
[Employee name];
Demo

SQL PIVOT on a variable amount of rows

I have the following data on a MSSQL Server:
Item No_ Unit Of Measure Qty Per Base UoM Rounding Precision
000001 PIECE 1 1.0
000001 PALLET 100 1.0
000001 BOX 12 1.0
000002 KG 1 1.0
000002 TON 1000 0.001
I am trying to get the following output:
Item No_ UoM1 Qty pb UoM1 RP1 UoM2 Qty pb UoM2 RP2 UoM3 Qty pb UoM3 RP3
000001 PIECE 1 1.0 PALLET 100 1.0 BOX 12 1.0
000002 KG 1 1.0 TON 1000 0.0001 NULL NULL NULL
I tried achieving this using the PIVOT operator but it does not seem te be correct.
What is the correct way to achieve my desired output?
For trully generic solution you need to use Dynamic-SQL.
But you say you want starting point, so I give you one. You can use:
LiveDemo
WITH cte AS
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY Item_No_ ORDER BY (SELECT 1)) AS rn
FROM #mytable
)
select Item_No_,
max(case when rn = 1 then Unit_Of_Measure end) UoM1,
max(case when rn = 1 then Qty_Per_Base_UoM end) [Qty pb UoM1],
max(case when rn = 1 then Rounding_Precision end) RP1,
max(case when rn = 2 then Unit_Of_Measure end) UoM2,
max(case when rn = 2 then Qty_Per_Base_UoM end) [Qty pb UoM2],
max(case when rn = 2 then Rounding_Precision end) RP2,
max(case when rn = 3 then Unit_Of_Measure end) UoM3,
max(case when rn = 3 then Qty_Per_Base_UoM end) [Qty pb UoM3],
max(case when rn = 3 then Rounding_Precision end) RP3,
max(case when rn = 4 then Unit_Of_Measure end) UoM4,
max(case when rn = 4 then Qty_Per_Base_UoM end) [Qty pb UoM4],
max(case when rn = 4 then Rounding_Precision end) RP4
from cte
group by Item_No_;
The point is that if your number of units is known in advance you can create hardcoded columns from 1 .. n.
For more info search Dynamic Pivot multiple columns. It is achievable, but first try to crack this solution.

Combine two queries, which include aggregations, into a single query

Table "tblCustomer":
Customer_id
created
field1
field2
cardno
1014
2010-05-25 12:51:59.547
Cell Phone
abc#lmn.com
1234567890
1015
2010-08-15 12:51:59.547
Email
abc#xyz.com
2345678891
Table "tbl_TransactionDishout":
Trnx_id
offerNo
TerminalID
Created
VirtualCard
1
1014
170924690436418
2010-05-25 12:51:59.547
1234567890
Expected Output:
Enrolled
Enrolled as Email
Enrolled as Text
Deals Redeemed
<First Date>
7
5
2
6
<Next Date>
9
3
6
14
I have two different queries which I need to combine into one.
First One:
SELECT CAST(FLOOR(CAST(t.created AS FLOAT )) AS Datetime) created,
COUNT(field1) Enrolled,
COUNT(CASE field1 WHEN 'E-mail' THEN 1 END) Enrolled_as_Email,
COUNT(CASE field1 WHEN 'Cell Phone' THEN 1 END) Enrolled_as_Cell
FROM tblCustomer as t
GROUP BY t.created
ORDER BY t.created DESC
Which Displays:
create
Enrolled
Enrolled_as_Email
Enrolled_as_Cell
2012-03-01 00:00:00.000
3
1
2
2012-02-29 00:00:00.000
1
0
1
Second One:
SELECT CAST(FLOOR(CAST(t.created AS FLOAT)) AS Datetime) created,
COUNT(*) [Deals_Redeemed]
FROM tbl_TransactionDishout t
LEFT JOIN tblCustomer c
ON t.VirtualCard = c.cardno
GROUP BY CAST(FLOOR(CAST(t.created AS FLOAT )) as Datetime)
ORDER BY t.created desc
Which Displays:
create
Deals_Redeemed
2012-03-02 00:00:00.000
1
2012-03-01 00:00:00.000
6
2012-02-28 00:00:00.000
1
2012-02-27 00:00:00.000
2
Now I want a record which contain date from both and should be combined into one.
But It's giving me the result of the date contained only in tblCustomer table..
How to get "Deals_redeemed"?
Note: relation between tbl_transaction and tblCustomer is having same cardno.
SELECT
CAST(t1.created AS DATE) created,
COUNT(t1.field1) Enrolled,
COUNT(CASE t1.field1 WHEN 'E-mail' THEN 1 END) Enrolled_as_Email,
COUNT(CASE t1.field1 WHEN 'Cell Phone' THEN 1 END) Enrolled_as_Cell,
COUNT(t2.created) Deals_Redeemed
FROM tblCustomer AS t1
LEFT JOIN tbl_TransactionDishout t2
ON t1.cardno = t2.VirtualCard
GROUP BY CAST(t1.created AS DATE)
ORDER BY CAST(t1.created AS DATE) DESC
Edit: Changed condition to cardno, and changed from FULL JOIN to LEFT JOIN.
You could Pivot():
select [create]
, sum([Email]+[Cell Phone]) as [Enrolled]
, max([Email]) as [Enrolled as Email]
, max([Cell Phone]) as [Enrolled as Cell Phone]
, max([Deal Redeemed]) as [Deals Redeemed]
from (
select [create]=created
, create1=created
, field1
from tblCustomer
union all
select [create]=created
, create1=created
, field1='Deal Redeemed'
from tbl_TransactionDishout
) p
pivot (
count(create1)
for field1 in ([Cell Phone],[Email],[Deal Redeemed])
) pv
group by [create]
order by [create]

Resources