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
Related
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);
One table
ID Name Email
101 George Georges1stEmail#hotmail.com
201 Fred Freds1stEmail#hotmail.com
301 Sally Sallys1stEmail#hotmail.com
101 George Georges2ndEmail#hotmail.com
101 George Georges3rdEmail#hotmail.com
301 Sally Sallys2ndEmail#hotmail.com
101 George Georges4thEmail#hotmail.com
101 George Georges5thEmail#hotmail.com
For the example below, I can't get the Email4 and Email5 fields to fit on this code page, but I'd like to either create another table that looks like this (with the addition of the Email4 and Email5):
ID Name Email1 Email2 Email3
101 George Georges1stEmail#hotmail.com Georges2ndEmail#hotmail.com Georges3rdEmail#hotmail.com
201 Fred Freds1stEmail#hotmail.com
301 Sally Sallys1stEmail#hotmail.com Sallys2ndEmail#hotmail.com
There can be a total of up to 5 emails for one ID.
Please and Thanks!
Everyone needs a little nudge from time-to-time.
If you have a known or maximum number of emails, you can perform a PIVOT in concert with the window function row_number()
Example
Select *
From (
Select ID
,Name
,EMail
,Item = 'Email'+left(row_number() over (partition by id order by email),2)
From YourTable
) src
Pivot (max(EMail) for Item in ([EMail1],[EMail2],[EMail3],[EMail4],[EMail5]) ) pvt
Returns
Or you can perform a Conditional Aggregration
Example
Select ID
,Name
,EMail1 = max(case when RN=1 then EMail else '' end)
,EMail2 = max(case when RN=2 then EMail else '' end)
,EMail3 = max(case when RN=3 then EMail else '' end)
,EMail4 = max(case when RN=4 then EMail else '' end)
,EMail5 = max(case when RN=5 then EMail else '' end)
From (
Select *
,RN = row_number() over (partition by id order by email)
From #YourTable
) src
Group By ID,Name
Returns
I am trying to write a query that will do the following.
I have a table with separate sales order lines on it. Each line details the customer, product sold, the price sold at, and the date of the sale.
I am trying to establish for each product code, what the last price we sold it for was for each separate customer.
For example using my input below I would expect Product code ABC to return '10' for Brian, '20' for Gary, and '50 for Sam.
Below is complete set of results I would expect for all product codes.
Input
Order No Customer Product Code Price Date
-----------------------------------------------------------
1 Brian ABC 10 12/04/2018
2 Brian ABC 14 01/04/2018
3 Gary ABC 20 12/04/2018
4 Gary ABC 35 12/04/2017
5 Sam ABD 40 06/08/2017
6 Sam ABC 50 20/08/2017
7 Adam ABE 20 15/06/2016
8 Adam ABE 30 17/03/2017
Output
Order No Customer Product Code Price Date 1 Brian ABC 10 12/04/2018 3 Gary ABC 20 12/04/2018 6 Sam ABC 50 20/08/2017 5 Sam ABD 40 06/08/2017 8 Adam ABE 30 17/03/2017
You can you Row_number() with partition BY [product code], [customer] for this.
Following query should work for you scenario
SELECT *
FROM (SELECT [order no],
[customer],
[product code],
[price],
[date],
Row_number()
OVER(
partition BY [product code], [customer]
ORDER BY [date] DESC) AS RN
FROM [table]) T
WHERE T.rn = 1
This is all about the row_number():
Allows you to partition (Similar to group) and provide an order
select top 1 with ties *
from table
order by row_number() over (partition by [Product Code],Customer order by date desc)
I think this is what you are looking for:
select a.* from #temp a join (
select customer, [product code], max(Date) maxdate
from #temp
group by customer, [product code])b
on a.customer=b.customer and a.date=b.maxdate and a.[product code]=b.[product code]
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]
I have a query that gives me all customer's and their last three order dates.
EX:
CustomerId DateOrdered
167 2006-09-16 01:25:38.060
167 2006-09-21 13:11:53.530
171 2006-08-31 15:19:22.543
171 2006-09-01 13:30:54.013
171 2006-09-01 13:34:36.483
178 2006-09-04 11:36:19.983
186 2006-09-05 12:50:27.153
186 2006-09-05 12:51:08.513
I want to know if there is a way for me to pivot it to display like this:
[CustomerId] [Most Recent] [Middle] [Oldest]
'167' '2006-09-21 13:11:53.530' '2006-09-16 01:25:38.060' 'NULL'
'171' '2006-09-01 13:34:36.483' '2006-09-01 13:30:54.013' '2006-08-31 15:19:22.543'
'178' '2006-09-04 11:36:19.983' NULL NULL
'186' '2006-09-05 12:51:08.513' '2006-09-05 12:50:27.153' NULL
;WITH YourQuery As
(
SELECT CustomerId, DateOrdered,
ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY DateOrdered DESC) AS RN
FROM Orders
)
select [CustomerId],
MAX(CASE WHEN RN=1 THEN DateOrdered END) AS [Most Recent] ,
MAX(CASE WHEN RN=2 THEN DateOrdered END) AS [Middle] ,
MAX(CASE WHEN RN=3 THEN DateOrdered END) AS [Oldest]
FROM YourQuery
WHERE RN<=3
GROUP BY [CustomerId]
Warning: Not Tested
I think you're looking for something like this. The specific joins and where clause may need some work, but basically your just joining the table back on itself to get one date each time.
SELECT C.CUSTOMERID, C.DATEORDERED, C2.DATEORDERED, C3.DATEORDERED
FROM CUSTOMER C
INNER JOIN CUSTOMER C2 ON C.CUSTOMERID = C2.CUSTOMERID
INNER JOIN CUSTOMER C3 ON C.CUSTOMERID = C3.CUSTOMERID
WHERE C.DATEORDERED = MAX(C.DATEORDERED)
AND C2.DATEORDERED < C.DATEORDERED AND
(C3.DATEORDERED IS NULL OR C2.DATEORDERED > C3.DATEORDERED)